首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Android:使用IPC的Messengers实现同步/阻塞API

Android:使用IPC的Messengers实现同步/阻塞API
EN

Stack Overflow用户
提问于 2014-09-11 14:59:55
回答 1查看 1.8K关注 0票数 1

我有一个后台服务,它运行在它自己独立的进程中,使用

代码语言:javascript
复制
android:process=":deamon"

在服务的清单条目中。我想从我的活动中与服务(远程进程)进行通信,并从它接收数据。我是通过向远程进程发送消息和从远程进程发送消息来做到这一点的,正如http://developer.android.com/guide/components/bound-services.html#Messenger中所描述的,并且按照他们的建议,我遵循

如果您希望服务响应,那么您还需要在客户机中创建一个Messenger。>然后,当客户机接收到onServiceConnected()回调时,它向>服务发送一条消息,该>服务在send()方法的replyTo参数中包含客户端的Messenger。

问题是,我需要提供一个阻塞/同步API来从远程服务中获取数据,我的" get“函数如何阻止调用方,然后返回传入Handler中接收到的数据?做这件事的最佳方法是什么?

EN

回答 1

Stack Overflow用户

发布于 2015-04-23 13:01:38

这是客户端消息传递部分的代码。

代码语言:javascript
复制
    SparseArray<CountDownLatch> lockArray = new SparseArray<>();
    SparseArray<Bundle> msgDataArray = new SparseArray<>();

    public Bundle sendAndWaitResponse(Message msg) throws 
                                RemoteException, InterruptedException {
        int msgId = msg.arg2;
        Log.d("PlatformConnector", "Sending message to service, Type: "
                                 + msg.what + ", msgId: " + msg.arg2);
        CountDownLatch latch = new CountDownLatch(1);
        lockArray.put(msgId, latch);
        platformMessenger.send(msg);
        latch.await();

        Bundle response = msgDataArray.get(msgId);
        lockArray.delete(msgId);
        msgDataArray.delete(msgId);

        return response;
    }

    void storeResponseAndNotify(Message msg) {
        int msgId = msg.arg2;
        // Because the message itself is recycled after Handler returns,
        // we should store only the data of message
        msgDataArray.put(msgId, msg.getData());
        lockArray.get(msgId).countDown();
    }


    private class ClientMessageHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            storeResponseAndNotify(msg);
        }
    }

这是使用上述代码的示例。RandomInt.getNextInt()是我自定义的静态方法,它用Random.nextInt()生成随机整数。

代码语言:javascript
复制
    public JSONObject doSomething(JSONObject object) {
        Message msg = Message.obtain(null, Constants.MESSAGE_SOMETHING, 0, RandomInt.getNextInt());
        Bundle bundle = new Bundle();
        bundle.putString(Constants.MESSAGE_DATA_SOMETHING, object.toString());
        msg.setData(bundle);
        try {
            Bundle responseData = sendAndWaitResponse(msg);
            return new JSONObject(responseData.getString(Constants.MESSAGE_DATA_RETURN));
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to send message to platform");
            e.printStackTrace();
        } catch (InterruptedException e) {
            Log.e(TAG, "Interrupted while waiting message from platform");
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return null;
    }

顺序如下,

  1. 客户端准备Message并将其arg2设置为一些随机整数(此整数将是用于同步的消息id )。
  2. 客户端准备新的CountDownLatch并将其放到LockArray中。
  3. 客户端使用sendAndWaitResponse()发送消息。它通过Messenger向服务发送消息,并调用latch.await()
  4. 服务流程接收消息并准备回复消息。此回复消息的arg2应该与接收到的消息相同。
  5. 服务通过Messenger在replyTo中向客户端发送回复消息。
  6. 客户端消息处理程序使用storeResponseAndNotify处理消息。
  7. 当客户端线程的阻塞完成后,响应数据将在msgDataArray中准备好。

CountDownLatch是用来阻塞和解除阻塞线程的简单开关。(http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)

SparseArray类似于HashMap,但对于较小的集合则更节省内存。(http://developer.android.com/reference/android/util/SparseArray.html)

小心不要阻塞Messenger的线程。Messenger在单个线程中运行,如果从handleMessage()阻塞,它将阻塞所有其他消息并导致脱锁问题。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25790854

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档