- Google API Reference to a Handler, which others can use to send messages to it. This allows for the implementation of message-based communication across processes, by creating a Messenger pointing to a Handler in one process, and handing that Messenger to another process.
Messenger允许跨进程基于消息的通信,通过在一个进程创建指向Handler的Messenger,然后在另外一个进程处理。
Note: the implementation underneath is just a simple wrapper around a Binder that is used to perform the communication.
Messenger是Binder的简单包装。 - 参见 Google Remote Messenger Sample
跨进程简单理解模型:
一、 Demo演示
同一个App中,将Service设置为remote,实现一个App多个进程。
Server端
Service代码
1 | import android.app.Service; |
配置在AndroidManifest.xml
1 | <!-- 设置remote之后,不仅仅是进程id不同了,就连应用程序包名也不一样了,包名后面还跟上了:remote标识。 --> |
Client端
Activity
1 | import android.content.ComponentName; |
Layout.xml
效果图
二、 源码分析
一句话总结:Messenger的内部实现的,实际上也是依赖于aidl文件实现的。
客户端向服务端通信
Server
1.服务端中的Service#onBind():
1 | public IBinder onBind(Intent intent){ |
2.其mMessenger.getBinder()具体实现:
1 | public IBinder getBinder() { |
3.其mTarget对象即是new Messenger(Handler)的Handler
1 | public Messenger(Handler target) { |
4.进入target.getIMessenger(),观察其实现细节:
1 | final IMessenger getIMessenger() { |
mTarget实质上是一个MessengerImpl对象,那么asBinder实际上是返回this,也就是MessengerImpl对象;
这是个内部类,可以看到继承自IMessenger.Stub,然后实现了一个send方法,该方法就是将接收到的消息通过 Handler.this.sendMessage(msg);
发送到handleMessage方法。
传统写aidl文件,aapt给我们生成什么,生成IXXX.Stub类,然后我们服务端继承IXXX.Stub实现接口中的方法。
没错,其实这里内部其实也是依赖一个aidl生成的类,这个aidl位于:frameworks/base/core/java/android/os/IMessenger.aidl.
1 | package android.os; |
Messenger并没有什么神奇之处,实际上,就是依赖该aidl文件生成的类,继承了IMessenger.Stub类,
实现了send方法,send方法中参数会通过客户端传递过来,最终发送给handler进行处理。
Client
客户端首先通过onServiceConnected拿到sevice(Ibinder)对象IMessenger.Stub.asInterface(service)拿到接口对象进行调用;
而,我们的代码中是mService = new Messenger(service);
1 | public Messenger(IBinder target) { |
其实质与平常写法一致!
客户端与服务端通信,实际上和我们平时的写法没有任何区别,通过编写aidl文件,服务端onBind利用Stub编写接口实现返回;客户端利用回调得到的IBinder对象,使用IMessenger.Stub.asInterface(target)拿到接口实例进行调用(内部实现)。
服务端向客户端通信
客户端send方法发送的是一个Message,这个Message.replyTo指向的是一个mMessenger,是我们自己初始化的,用于服务端向客户端通信。
那么将消息发送到服务端,肯定是通过序列化与反序列化拿到Message对象,我们看下Message的反序列化的代码:
Message
1 | private void readFromParcel(Parcel source) { |
主要看replyTo,调用的是Messenger.readMessengerOrNullFromParcel
1 | public static Messenger readMessengerOrNullFromParcel(Parcel in) { |
通过上面的writeMessengerOrNullToParcel可以看到,它将客户端的messenger.mTarget.asBinder()对象进行了恢复,客户端的message.mTarget.asBinder()是什么?
客户端也是通过Handler创建的Messenger,于是asBinder返回的是:
1 | public Messenger(Handler target) { |
那么asBinder,实际上就是MessengerImpl extends IMessenger.Stub中的asBinder了。
IMessenger.Stub
1 |
|
那么其实返回的就是MessengerImpl对象自己。到这里可以看到message.mTarget.asBinder()其实返回的是客户端的MessengerImpl对象。
最终,发送给客户端的代码是这么写的:
1 | msgfromClient.replyTo.send(msgToClient); |
这个mTarget实际上就是对客户端的MessengerImpl对象的封装,那么send(message)(屏蔽了transact/onTransact的细节),这个message最终肯定传到客户端的handler的handleMessage方法中。
一句话总结:
- 客户端通过bindService拿到服务端的Messenger对象;
- 客户端给服务端发送消息的时候,使用Messager.replyTo携带客户端的Messenger对象到服务端;
- 这样,客户端/服务端互相持有对方Binder对象(MessengerImpl);
- 实质还是利用了AIDL的方式。