【问题标题】:Android: How to implement "distributed control"Android:如何实现“分布式控制”
【发布时间】:2011-05-26 17:06:56
【问题描述】:

{为与 android-developers 论坛的交叉发帖致歉。那里没有收到任何答复}

我有一个有趣的设计挑战:

我有一个前端(活动)和一个后端(用本机 C/C++ 编写) 代码。后端是一个复杂的对象,它部分控制 应用程序流和一旦启动在它自己的线程中运行。所以我有 “分布式控制”场景。

Activity 需要能够异步发送消息到 后端然后采取某些行动。但是后端也需要 能够向 Activity 异步发送消息, 它通过改变 UI、触发方法等来响应。

基本上我需要的是双向监听器。

所以后端向屏幕发送消息(拍照,提示用户,获取 位置,现在再拍一张照片等)和屏幕做它需要的 去做。但除此之外,屏幕应该还可以调用 后端侦听器发送回消息(捕获的相机图像,系统 生成 - “我暂停/销毁”消息等)在回调 这些事件。主要问题是这都是异步的。

如果没有紧耦合,这可能吗?这甚至可能吗?

我想到了 Asynctask/handlers(但这是一条单向的街道) 通知 UI 线程),观察者模式(两个对象都将 观察者/可观察者?)但对从哪里开始感到困惑。有什么想法吗, 链接会很有帮助。

【问题讨论】:

  • 您现在有什么潜在的解决方案吗?如果没有,如果没有其他人回复,我可以给你一个最坏情况的解决方案。
  • 没有潜在的解决方案 :-( 。请给出你的解决方案。

标签: android design-patterns


【解决方案1】:

在您的本机代码中,您可以使用 JNI 从您的 VM 中获取类(和对象),一旦您获得了一个类(或对象),您就可以找到方法并调用它们(类的静态方法,所有对象的方法)。在我看来,简单的解决方案是在你的 java 类中提供一个帮助器,它封装了本地方法并调用本地代码。

过去,我需要让本机代码确定其线程是否已在 Java 级别中断。 Java 提供了 java.lang.Thread.currentThread() 作为静态来寻找自己的线程,而 java.lang.Thread.isInterrupted() 则 [非破坏性地] 确定中断状态。我使用以下方法在本机级别解决了这个问题;也许您可以根据自己的需要使用它(当然,适当地适应消息发送):

/* JavaThread: this class is a simple wrapper to be used around    */
/* JNI's Thread class. It locates the provided functions as needed */
/* and when it is destroyed (such as going out of scope) it will   */
/* release its local references.                                   */
class JavaThread
{
public:
    JavaThread(JNIEnv *env)
    {
        mEnv = env;

        /* find the Java Thread class within the JVM: */
        mThread = mEnv->FindClass("java/lang/Thread");

        /* find the Thread.currentThread() method within the JVM: */
        mCurrentThreadMID = mEnv->GetStaticMethodID(mThread, "currentThread", "()Ljava/lang/Thread;");

        /* find the current thread's isInterrupted() method: */
        mIsInterruptedMID = mEnv->GetMethodID(mThread, "isInterrupted", "()Z");
    }
    ~JavaThread()
    {
        if (mThread)
        {
            mEnv->DeleteLocalRef(mThread);
            mThread = 0;
        }
    }

    bool isInterrupted() {
        bool bResult;
        if (!mThread)           return false;
        if (!mIsInterruptedMID) return false;

        /* find the current thread (from the JVM's perspective): */
        jobject jCurrentThread = (jobject)mEnv->CallStaticObjectMethod(mThread, mCurrentThreadMID);
        if (NULL == jCurrentThread) return false;

        /* see if the current thread is interrupted */
        bResult = (bool)mEnv->CallBooleanMethod(jCurrentThread, mIsInterruptedMID);

        /* delete the current thread reference */
        mEnv->DeleteLocalRef(jCurrentThread);

        /* and return the result */
        return bResult;
    }

private:
    JNIEnv    *mEnv;
    jclass     mThread;
    jmethodID  mCurrentThreadMID;
    jmethodID  mIsInterruptedMID;
};

实例化基于提供给您的本地方法的 JNIEnv *,调用 isInterrupted() 方法的简单 allocate/call/deallocate 代码行是:

if (JavaThread(env).isInterrupted()) { ... }

【讨论】:

  • +1 用于提供有关从 JNI 检查线程中断的信息。我知道 Java 部分,但不知道其他部分。但是,我的主要问题并不是真正跟踪彼此的线程。它涉及两个对象监听彼此的回调以及如何实现它。
  • @OceanBlue -- 是的,当然。我希望您可以使用我的(工作生产)代码作为示例来展示如何从本机代码访问 Java 中的 something。一旦你知道如何做到这一点,在你自己的类中提供你自己的方法来解决问题应该不难,本机代码根据需要调用你的 Java 方法。例如,在本机级别,您可以启动一个新线程,该线程调用您提供的阻塞 Java 方法,当收到适当的消息时,该方法将解除阻塞。
  • 哦,我想我明白你在说什么了。我通过在活动中实现侦听器接口来实现整个“如何从本机访问 Java 方法”。然后我将“this”的引用传递给后端。本机只是调用侦听器的方法来让它做它想做的事。这避免了“阻塞Java代码”。
  • 回到最初的问题,忘记整个原生的事情,即使有两个 java 类的方法在两个线程中运行。他们可以BOTH 实现监听器、保持对彼此的引用并调用彼此的监听方法吗?听起来可怕的耦合方式。那么该怎么做呢??
【解决方案2】:

使用阻塞队列怎么样,因为你的描述让我想起了并行编程课上的经典生产者-消费者问题。

http://en.wikipedia.org/wiki/Producer-consumer_problem

Java 1.5 似乎也有一个阻塞队列的实现,如果它在 Android 上可用,我想不起来了。

http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html

我想您可以设置 2 个单向阻塞队列用于单向通信。 Q1 将前端作为生产者,后端作为消费者。 Q2 将前端作为消费者,后端作为生产者。

您还可以将“命令”设计模式用于通信“消息”。

http://en.wikipedia.org/wiki/Command_pattern

HTH

【讨论】:

  • 感谢您的回答和分享链接。如果它解决了我的问题,我会更多地研究阻塞队列和命令模式......
猜你喜欢
  • 1970-01-01
  • 2011-07-23
  • 1970-01-01
  • 2017-09-23
  • 2014-01-17
  • 2014-03-09
  • 2010-09-10
  • 2015-11-17
  • 2012-10-07
相关资源
最近更新 更多