前言
Messenger中文意思是送信者,通过Messenger我们可以在不同进程之间传递Message对象,其底层也是通过上文讲到的AIDL实现的,先来看看基本用法
一、基本用法
以客户端发送消息给服务端,服务端回复一个消息给客户端为例。
- // 运行在其它进程
- class MessengerService : Service() {
- class MessengerHandler : Handler() {
- val TAG = "MessengerHandler"
- override fun handleMessage(msg: Message?) {
- when (msg?.what) {
- ADD_BOOK -> {
- // 必须设置classLoader不然会抛出异常
- msg.data.classLoader = Thread.currentThread().contextClassLoader
- Log.d(TAG, "do add book ${msg.data.get("book")}")
- val replyMessage = Message.obtain(null, REPLY_ADD_BOOK)
- val bundle = Bundle()
- bundle.putString("reply", "我收到了响应")
- replyMessage.data = bundle
- msg.replyTo.send(replyMessage)
- }
- ALL_BOOKS -> {
- Log.d(TAG, "do all books")
- }
- }
- }
- }
- override fun onBind(intent: Intent?): IBinder? {
- val messenger = Messenger(MessengerHandler())
- return messenger.binder
- }
- }
- 复制代码
接着在MainActivity中绑定服务,代码如下
- class MainActivity : AppCompatActivity() {
-
- private lateinit var connection: ServiceConnection
- private lateinit var replyMessenger: Messenger
- private var messenger: Messenger? = null
-
- class GetReplyHandler : Handler() {
- private var TAG = "MainActivity"
- override fun handleMessage(msg: Message?) {
- when (msg?.what) {
- REPLY_ADD_BOOK -> {
- Log.d(TAG, msg.data.getString("reply"))
- }
- }
- }
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- connection = object : ServiceConnection {
- override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
- messenger = Messenger(service)
- }
- override fun onServiceDisconnected(name: ComponentName?) {
- }
- }
- replyMessenger = Messenger(GetReplyHandler())
- val intent = Intent(this, MessengerService::class.java)
- bindService(intent, connection, Context.BIND_AUTO_CREATE)
- }
-
- fun send(v: View) {
- val msg = Message.obtain(null, ADD_BOOK)
- // msg.obj = Book(0, "第0本书") 不能使用obj跨进程传递自定义的Parcelable对象,使用Bundle因为其可以设置classLoader
- val msg = Message.obtain(null, ADD_BOOK)
- val bundle = Bundle()
- bundle.putParcelable("book", Book(0, "第0本书"))
- msg.data = bundle
- msg.replyTo = replyMessenger
- messenger?.send(msg)
- }
-
- override fun destroy() {
- unbindService(connection)
- }
- }
- 复制代码
注意send方法内部发送的Parcelable类(这里是Book)在服务端必须也要存在,这样当调用MainActivity的send方法时就会服务进程就会打印出do add book,下面就来看看该过程的源码
二、源码分析
- 客户端发送消息给服务端
首先我们在MessengerService的onBind中创建了一个Messenger实例,所以我们就从Messenger构造器开始说起
- public Messenger(Handler target) {
- mTarget = target.getIMessenger();
- }
- 复制代码
继续看看Handler的getIMessager
- final IMessenger getIMessenger() {
- synchronized (mQueue) {
- if (mMessenger != null) {
- return mMessenger;
- }
- mMessenger = new MessengerImpl();
- return mMessenger;
- }
- }
- 复制代码
刚开始mMessenger肯定为null,继续看看MessengerImpl
- private final class MessengerImpl extends IMessenger.Stub {
- public void send(Message msg) {
- msg.sendingUid = Binder.getCallingUid();
- Handler.this.sendMessage(msg);
- }
- }
- 复制代码
这里居然有个Stub!瞬间想起了AIDL,于是就去找了找有没有IMessenger.aidl这个文件,最终找到了该文件,文件内容如下
- oneway interface IMessenger {
- void send(in Message msg);
- }
- 复制代码
这里的oneway表示调用send方法并不会挂起当前线程等待服务端执行,而是会立即返回,send方法实现为将收到的消息发送给创建Messenger时的入参,至此服务端的Messenger使用分析完毕接着看看客户端中Messenger的使用,在onServiceConnected中通过传入的Binder对象构造了Messenger对象。
- public Messenger(IBinder target) {
- mTarget = IMessenger.Stub.asInterface(target);
- }
- 复制代码
调用asInterface(上篇文章有讲到)拿到IMessenger.Stub.Proxy实例赋值给mTarget,最后客户端通过调用Messengr.send发送消息
- public void send(Message message) throws RemoteException {
- mTarget.send(message);
- }
- 复制代码
不管这里send是个直接调用还是IPC调用都会调用到以下MessengerImpl的send方法,该方法又把消息发送到了对应的Handler,因此服务端的Handler就能收到消息了
- 服务端收到消息回复客户端
注意客户端将replyMessenger设置给了Message.replyTo然后发送消息,这个过程中会调用Message.writeToParcel
- public void writeToParcel(Parcel dest, int flags) {
- if (callback != null) {
- throw new RuntimeException(
- "Can't marshal callbacks across processes.");
- }
- dest.writeInt(what);
- dest.writeInt(arg1);
- dest.writeInt(arg2);
- if (obj != null) {
- try {
- Parcelable p = (Parcelable)obj;
- dest.writeInt(1);
- dest.writeParcelable(p, flags);
- } catch (ClassCastException e) {
- throw new RuntimeException(
- "Can't marshal non-Parcelable objects across processes.");
- }
- } else {
- dest.writeInt(0);
- }
- dest.writeLong(when);
- dest.writeBundle(data);
- Messenger.writeMessengerOrNullToParcel(replyTo, dest);
- dest.writeInt(sendingUid);
- }
- 复制代码
又会调用到Messenger.writeMessengerOrNullToParcel
- public static void writeMessengerOrNullToParcel(Messenger messenger,
- Parcel out) {
- out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder()
- : null);
- }
- 复制代码
向Parcel中写入了一个MessengerImpl实例(Binder),然后在IPC结束后会调用Message.readFromParcel
- private void readFromParcel(Parcel source) {
- what = source.readInt();
- arg1 = source.readInt();
- arg2 = source.readInt();
- if (source.readInt() != 0) {
- obj = source.readParcelable(getClass().getClassLoader());
- }
- when = source.readLong();
- data = source.readBundle();
- replyTo = Messenger.readMessengerOrNullFromParcel(source);
- sendingUid = source.readInt();
- }
- 复制代码
又调用到了Messenger.readMessengerOrNullFromParcel
- public static Messenger readMessengerOrNullFromParcel(Parcel in) {
- IBinder b = in.readStrongBinder();
- return b != null ? new Messenger(b) : null;
- }
- 复制代码
如果是跨进程传递那么读取的会是一个BinderProxy对象,通过该BinderProxy构造Messenger对象其内部的mTarget就会是一个IMessenger.Stub.Proxy实例,因此服务端就可以调用客户端的对应方法了