Android IPC之Messenger分析2

125 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情

双向通信实现

如果服务端收到消息需要回复客户端,应该怎么实现呢?

客户端也需要创建一个Messenger对象,接着创建一个对应的处理Handler对象,最后在onServiceConnected方法中,把Messenger对象赋值给message.replyTo,通过mService.send(message)方法发送给服务端,服务端可以通过replyTo的messenger对象给客户端发消息,从而完成双向通信,实现如下:

private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        //获取服务端关联的Messenger对象
        Messenger mService=new Messenger(service);
        //创建Message对象
        Message message = Message.obtain();
        Bundle bundle = new Bundle();
        bundle.putString("client","hello");
        message.setData(bundle);
        //在message中添加一个回复mReplyMessenger对象,server端可通过此来给client发消息
        message.replyTo = mReplyMessenger;
        try {
            mService.send(message);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
};

private ReplyHandler mReplyHandler = new ReplyHandler();
private Messenger mReplyMessenger = new Messenger(mGetReplyHandler);
public static class ReplyHandler extends Handler{
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        Bundle bundle = msg.getData();
        String serviceMsg = bundle.getString("server");
        Log.i(TAG, "来自服务端的回复:"+serviceMsg);
    }
}

服务端在AndroidManifest.xml中对service进行配置:

<service android:name=".model.MyService"
     android:exported="true"
     <intent-filter>
          <action android:name="com.hly.learn.server.action" />
     </intent-filter>
</service>

其实Messenger底层也是AIDL。客户端和服务端通讯,就是普通的AIDL,客户端实例化Stub之后,通过Stub的send方法把消息发到服务端。服务端和客户端通讯:服务端通过解析message的replyto,获得客户端的Stub,然后通过send方法发送到客户端。

三.源码分析

从上面实例使用可以看到,在Service的onBind()方法中通过mMessenger.getBinder()来返回对应的IBinder,先看一下Messenger的源码实现:

a.Messenger.java
public final class Messenger implements Parcelable {
    private final IMessenger mTarget;

    public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }

   public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }

   public IBinder getBinder() {
        return mTarget.asBinder();
    }
    ......
    ......
    public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }
}

从Messenger的源码可以看到,主要有四个方法:

  1. 提供给服务端的构造方法,需要传入Handler实例,在方法内部通过Handler返回IMessenger实例;
  2. 提供给客户端的send()方法,发送message到服务端;
  3. 提供给服务端在onBind()返回Binder的方法;
  4. 提供给客户端在onServiceConnected()内部获取Messenger实例的方法;

Messenger内部同时提供了服务端和客户端对应的方法,getBinder()是通过mTarget来返回的,mTarget是通过Handler的getIMessenger()来返回的,具体实现是在Handler内部。