Messenger是什么?

MessengerAndroid 中和 AIDL 一样,用于进程间通信的技术,也是基于 AIDL 的封装。

Messenger怎么用?

服务端

服务端需要继承 Service 这个没什么好说的。

在讲 AIDL 的时候,服务端要自己实现 IBinder 并通过 onBind 方法返回给客户端使用。 Messenger 也是类似的,不过就不需要再写 .aidl 文件了。只需要创建一个 Messenger 对象,然后在 onBind 中把 Messenger.binder 给返回出去就行了。

Messenger 的构造方法中,需要创建一个 Handler 用来处理客户端发过来的消息,这样我们就可以专注于业务逻辑的开发了。这就有点像线程间通信了,对与不熟悉的人就可以快速上手,学习成本就小多了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class MessengerService : Service() {
    val mMessenger = Messenger(object : Handler() {
             override fun handleMessage(msg: Message) {
                 super.handleMessage(msg)
                 println(msg)
             }
    })

    override fun onBind(intent: Intent?): IBinder? {
        return mMessenger.binder
    }
}

客户端

客户端和 AIDL 一样需要先连接上服务端,然后拿到服务端的 Binder

拿到服务端之后需要用 Messenger 包装一下,然后就可以通过 Messenger.send 方法发送消息给服务端了。

当然发送的消息要通过 Message 来传递,也就是 whatarg1arg2Bundle 来传递了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class MainActivity : AppCompatActivity() {
    private val TAG = MainActivity::class.simpleName

    var mMessenger:Messenger? = null

    val conn = object : ServiceConnection {
        override fun onServiceDisconnected(name: ComponentName?) {
            Log.d(TAG,"onServiceDisconnected")
        }

        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            mMessenger = Messenger(service)
            sendMsgToServer()
        }

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        bindService(Intent(this, MessengerService::class.java), conn, Context.BIND_AUTO_CREATE)

    }

    fun sendMsgToServer() {
        val msg = Message.obtain(null, 1)
        mMessenger?.send(msg)
    }
}

Messenger的原理

我们从服务端看起,在服务端的 onBind 中返回的是 Messenger 中的 binder

1
2
3
4
5
6
7
public IBinder getBinder() {
    return mTarget.asBinder();
}

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

getBinder 中返回的是 mTarget.asBindermTarget 是从 Handler.getIMessenger 中得到的,跟进去看看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
final IMessenger getIMessenger() {
    synchronized (mQueue) {
        if (mMessenger != null) {
            return mMessenger;
        }
        mMessenger = new MessengerImpl();
        return mMessenger;
    }
}

private final class MessengerImpl extends IMessenger.Stub {
    public void send(Message msg) {
        msg.sendingUid = Binder.getCallingUid();
        Handler.this.sendMessage(msg);
    }
}

可以看到返回的是 MessengerImplMessengerImpl 继承 IMessenger.Stub 这个和我们之前讲 AIDL 有些类似,打开 AndroidXRef ,搜索一下 IMessenger.aidl 还真的找到有这个文件 Cross Reference: /frameworks/base/core/java/android/os/IMessenger.aidl ,内容如下

1
2
3
4
5
6
7
8
package android.os;

import android.os.Message;

/** @hide */
oneway interface IMessenger {
    void send(in Message msg);
}

里面只有一个方法 send 这个就是用来发消息的了。有兴趣的可以用 aidl 工具来生成对应的 java 文件。接下来我们来看客户端

1
2
3
4
5
6
public Messenger(IBinder target) {
    mTarget = IMessenger.Stub.asInterface(target);
}
public void send(Message message) throws RemoteException {
    mTarget.send(message);
}

在服务端连接成功后,我们通过 Messenger 的构造方法把 IBinder 传递进去,在构造方法里通过 asInterface 转换为服务端的代理对象,使用 send 来和服务端通信,也是唯一的方法。

看到这里也就明白了,其实 Messenger 也是使用的 AIDL 来进行跨进程调用,只不过提供了一层封装,更加容易上手,并且还和 Handler 巧妙的结合起来,使得 Handler 既能处理多线程还能处理多进程。

总结

这样的设计把一个比较复杂的事物用一个我们日常比较熟悉的事物封装可以达到降低学习成本的目的。

需要注意的是 Messenger 只适合一对多的串行通信,并且不能有返回值,不能很好处理高并发场景。

参考

  • Android开发艺术探索