What is a Messenger

Messenger is also an IPC solution for message-based communication across processes.

What does “message based” mean? Handler is our most common messaging mechanism, so Messenger is like using a Handler for a consumer. Messenger is essentially an upper layer of AIDL, and you can read my other AIDL introduction. Cross-processes in Android are all based on Binder, packaged for certain scenarios to make them easier to use.

Use the Messenger

The service side

const val MSG_CLIENT = 0x110 const val MSG_SERVER = 0x111 class MessengerService: Service() { private val mMessenger = Messenger(object : Handler(Looper.getMainLooper()){ override fun handleMessage(msg: Message) { Log.d("MessengerService", "CurrentThread ->" + thread.currentThread ().name) when(msg.what) {MSG_CLIENT -> { D ("MessengerService", "name=" + bundle.get("name") + "; age=" + bundle.get("age") + " ; MSG val replyMsg = message.obtain () replymsg. what = MSG_SERVER val bundleToC = Bundle() bundletoc.putString (" MSG ", "Thank you, I got it." ) replymsg. data = bundleToC // Server send to client, MSG. Replyto. send(replyMsg)}} super.handleMessage(MSG)}}); override fun onBind(intent: Intent?) : IBinder? { return mMessenger.binder } }Copy the code

Messenger itself is an AIDL wrapper, so mMessenger. Binder is returned via service in the onBind method. It then receives the MSG within the handleMessage method as if it were using a Handler. Again, declare the service in the androidmanifest.xml file.

<service android:name=".MessengerService"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.messengerservice"></action>
    </intent-filter>
</service>
Copy the code

The client

The first step on the client side is to bind the Service again.

private val connection = object: ServiceConnection{ override fun onServiceDisconnected(className: ComponentName?) { mServiceMessenger = null } override fun onServiceConnected(className: ComponentName? , service: IBinder?) {mServiceMessenger = Messenger(service)}} val intent = intent (); intent.component = ComponentName("com.example.interprocess", "com.example.service.MessengerService") bindService(intent, connection, Context.BIND_AUTO_CREATE);Copy the code

The only difference from aiDL is that the onServiceConnected IBinder argument is used to build a Messenger instance.

Finally, MSG is sent using the send method:

val msg = Message.obtain() msg.what = MSG_CLIENT val bundle = Bundle() bundle.putString("name", name) bundle.putInt("age", age) bundle.putString("sex", sex) bundle.putString("height", height) msg.data = bundle msg.replyTo = mClientMessenger mServiceMessenger? .send(msg)Copy the code

It feels like you’re using Handler to send a message, and the actual data needs to be stored in the Bundle, and one thing to note here is that if you want to stuff the Bundle with objects that implement Parcelable, — A ClassNotFoundException will be thrown when the server receives a parameter. Since the bundles of the two apps are loaded by different class loaders, it is still not a good idea to use the basic type data in the Bundle, which is not a good idea for large amounts of complex data.

Therefore, I personally believe that message-based Messenger gives us more convenience to use and understand than AIDL but is not suitable for managing complex data communication across processes.

As you can see, the above code also has a mClientMessenger assigned to msg.replyTo, which is the messenger from which the client receives the message. Remember that on the server side the callback to the client is msg.replyto.send (replyMsg), and everything is concatenated, as is the handling of messenger messages on the client side:

private val mClientMessenger = Messenger(object : Handler(Looper.getMainLooper()) {
    override fun handleMessage(msg: Message) {
        when(msg.what){
            MSG_SERVER -> {
                Log.d("MainActivity", "currentThread ->" + Thread.currentThread().name)
                Log.d("MainActivity", "server callback = " + msg.data.getString("msg"))
            }
        }
        super.handleMessage(msg)
    }
})
Copy the code

This is due to handler input to the Messenger constructor. Handler specifies Looper for the main thread, so the message will be received on the main thread.

Messenger principle

We’ve already mentioned that Messenger is a wrapper around AIDL, so let’s see what it is.

An instance of Handler is always passed when creating Messenger:

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

Let’s go to handler and see

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);
    }
}
Copy the code

MessengerImpl in handler inherits IMessenger.Stub

// IMessenger.aidl
oneway interface IMessenger {
    void send(in Message msg);
}
Copy the code

This is exactly a standard AIDL interface, but the system does this layer of encapsulation for us and then converts it to the familiar message mechanism through handlers. ** Note the oneway keyword, indicating that messenger is an asynchronous call. Parcelable implements the Parcelable interface and declares the aiDL interface:

/ / package path: / frameworks/base/core/Java/android/OS/Message. The aidl package. Android OS; parcelable Message; / / package path: / frameworks/base/core/Java/android/OS/Message. Java public final class Message implements Parcelable {/ /... }Copy the code

Again, the way Messenger communicates with each other is by setting a MSG. ReplyTo variable, which is also a Messenger variable. Remember that AIDL introduced delivery support for the AIDL interface, So the client mClientMessenger can be passed to the server, and then the send method can be called to send back the data. The specific principle depends on Binder principle.

conclusion

  • Messenger is cross-process communication based on a messaging mechanism that encapsulates AIDL.
  • Messenger is not well suited for managing the cross-process transfer of complex data.
  • Messenger naturally supports asynchronous cross-process calls.
  • Both client and server are in the main thread when receiving cross-process messages, eliminating the need to switch threads.