Talking about the messenger of Android IPC

Source: Internet
Author: User

Before writing an article about the aidl of IPC, see the Aidl of Android IPC for details. Let's introduce another kind of ipc-messenger today.

I. Overview.

First Look at Messenger introduction,

Reference to a Handler, which others can with send messages to it. This allows for the implementation of message-based communication across  processes, by creating a Messenger pointing t o a Handler in one process, and handing this Messenger to another process.
Probably means to send a message through handler. Allows the implementation of a message-based communication in a process, creates a messenger in a process, points to a handler, and passes the messenger to another process.

In other words, Messenger sends messages through handler and can communicate between different processes.

This is illustrated by a picture,


This diagram basically illustrates the upper-level workflow of Messenger. The summary is as follows:

The use of 1.Messenger needs to have the service side and the client;

2. The client needs to bind the remote connection, after the successful binding, the remote IBinder object can be obtained, and the remote Messenger object can be obtained through the IBinder;

3. When sending a message to the server, it is necessary to use the Messenger object on the server side, and the Messenger object of the client can be assigned to the ' ReplyTo ' attribute of the message and passed to the server.

4. Sending a message to the client requires the use of the client's Messenger object, which is obtained from the ' ReplyTo ' attribute of the message sent by the client.

The following is still an example of how Messenger's entire process is demonstrated.

Second, the example.

Create two apps, one for the server and one for the client.

1. Service-side implementation.

Once the app is created, create a service,

/** * Server */public class Messengerservice extends service {private static final String TAG = "Messengerservice";    private static final int what = 0x101; Handler Mhandler = new Handler () {@Override public void Handlemessage (Message msg) {Super.handl            EMessage (msg); Switch (msg.what) {case://Accept message from client bundle bundle= (bundle)                    Msg.obj;                    String str = (string) bundle.get ("str");                    LOG.E (TAG, "The server has received a message from the client");                    LOG.E (TAG, "message is---->" + str);                    Send data to client message message = Message.obtain ();                    Bundle bundle1= New Bundle (); Bundle1.putstring ("str", "I already know, come on, watch you!"                    ");                    Message.obj = Bundle1;                    message.what=0x102; try {//Send message to Client Msg.replyTo.send (msg);//First get m passed from clientEssenger object, and then calls the Messenger object's send () method} catch (RemoteException e) {e.printstackt                    Race ();            } break;    }        }    };    Private Messenger messenger = new Messenger (Mhandler);        @Override public void OnCreate () {super.oncreate ();    LOG.D (TAG, "onCreate:");    } @Nullable @Override public ibinder onbind (Intent Intent) {return messenger.getbinder (); }}

Implement the service's Onbind () method, call ' Messenger.getbinder () ' To return a ibinder, return the IBinder we will receive and use on the client. Creates a handler that receives a message that is delivered by the client, and then sends a message to the client when the message is received. This is what the service side is all about!

Be sure to remember that when sending a message, the data cannot be thrown directly to the message, otherwise it will be an error, as shown below:

Java.lang.RuntimeException:Can ' t marshal non-parcelable objects across processes.
Because the data passed by the binder transaction is called a parcel (Parcel), the Parcelable interface must be implemented, otherwise communication between the two applications cannot be made. So, if you need to carry the data in the message, use the bundle object because it gives the class and implements the Parcelable interface.
Also remember to register the service.

...  <service            android:name= ". Messengerservice "            android:exported=" true ">            <intent-filter>                <action android:name=" Cn.xinxing.messengerservice "></action>                <category android:name=" Android.intent.category.DEFAULT " />            </intent-filter>        </service>, ....
The role of android:exported is "whether to support other applications calling the current component", "true" allows to be started; false is not allowed to be started. and set the "Action" property, which makes it easy for us to invoke the service implicitly.

Everything OK, you can run the program!

Ps:

IBinder is an interface. IBinder is the basic interface for remote objects and is a core part of the lightweight remote invocation mechanism designed for high performance. But it is not only used for remote calls, but also for in-process calls. This interface defines the protocol that interacts with the remote object. Do not implement this interface directly, but should derive from Binder.

The main API for IBinder is Transact (), which corresponds to another method that is binder.ontransact (). The first method allows you to send a call to the remote IBinder object, and the second method enables your own remote object to respond to the received call. IBinder APIs are executed synchronously, such as Transact () until the Binder.ontransact () method Call of the other party is complete before returning. This is undoubtedly the case when the invocation occurs within the process, and the same effect is done with the help of the IPC during the process.

2. Client implementation.

public class Mainactivity extends Appcompatactivity {private static final String TAG = "mainactivity";    private static final int what = 0x102;    Private Boolean isconn; Handler Mhandler = new Handler () {@Override public void Handlemessage (Message msg) {Super.handl            EMessage (msg); Switch (msg.what) {case WHAT://Accept messages sent from the server bundle bundle= (bundle)                    Msg.obj;                    String str = (string) bundle.get ("str");                    LOG.E (TAG, "Client service has received the message on the service side");                    LOG.E (TAG, "message is---->" + str);            Break    }        }    };    Private Messenger Mclientmessenger = new Messenger (Mhandler);        Private Messenger Mservicemessenger; Serviceconnection serviceconnection = new Serviceconnection () {@Override public void onserviceconnected (Com            Ponentname name, IBinder service) {LOG.E (TAG, "Connection service success---->"); MServicemessenger = new Messenger (service);            Isconn = true;            Message message = Message.obtain ();            Bundle Bundle=new Bundle (); Bundle.putstring ("str", "Hello!" I'm a program ape!            ");            Message.obj=bundle;            Message.what = 0x101;            Message.replyto = Mclientmessenger;            try {mservicemessenger.send (message);            } catch (RemoteException e) {e.printstacktrace (); }} @Override public void onservicedisconnected (componentname name) {LOG.E (TAG, "Connection Servic            E---->disconnected ");            Mservicemessenger = null;        Isconn = false;    }    };        @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);        Setcontentview (R.layout.activity_main); Findviewbyid (R.id.btn_start_service). Setonclicklistener (New View.onclicklistener () {@Override publi c void OnClick (View V) {bindservice ();    }        });        /** * Bind Remote Connection service */private void Bindservice () {Intent Intent = new Intent ();        Intent.setaction ("Cn.xinxing.messengerservice");    Bindservice (Intent, serviceconnection, context.bind_auto_create);        } @Override protected void OnDestroy () {Super.ondestroy ();        if (isconn) {unbindservice (serviceconnection); }    }}

There is a button on the screen that binds the remote Connection service when the button is clicked, the message is sent when the binding succeeds, the handler is used to receive the message, and when the activity is destroyed, unbind.

The whole implementation is still relatively simple.

After running the client, click on the button, look at the log output,


The remote Connection service is successfully bound, then the server outputs log,


Last client log output,


Summary: The entire process is that when the button is clicked, the remote Connection service is bound, the binding succeeds, and the Messenger object of the remote service is received, then the Messenger object is used to send the message, and the client's Messenger The object is also sent to the server, and when the server receives the message, it outputs the message content sent by the client, gets the Messenger object from the client, and then uses the Messenger object to send a message to the client. When the client receives the message, it outputs log.

On the whole, using Messenger to implement IPC is relatively simple compared to aidl. Below we through Messenger's source code to analyze, its internal realization.

Third, source code analysis.

Let's look at how Messenger is constructed,

  Private final IMessenger Mtarget;       Public Messenger (Handler target) {        mtarget = Target.getimessenger ();    }

The construction method passes a Handlerand then passes the Handler imessenger object to the mtarget object (Messengerimpl )。 The following is a concrete implementation of Handler's Getimessenger () ,

    Final IMessenger Getimessenger () {        synchronized (mqueue) {            if (Mmessenger! = null) {                return mmessenger;< c15/>}            Mmessenger = new Messengerimpl ();            return mmessenger;        }    }

Instantiates a Messengerimpl object, and then returns a IMessenger object. Which Messengerimpl the source code as follows,

    Private Final class Messengerimpl extends Imessenger.stub {public        void Send (Message msg) {            Msg.sendinguid = Binde R.getcallinguid ();            Handler.this.sendMessage (msg);        }    }
See here imessenger.stub, looks very familiar Ah! This is not the realization of aidl! Bingo! Yes! MessengerThe bottom is actually aidl! Just MessengerIt has been encapsulated for us, and we do not need to care about the specifics of Aidl.

IMessenger Source is located in ' \base\core\java\android\os\imessenger.aidl ', you can see it is a aidl file, the following is its source code,

Package Android.os;import android.os.message;/** @hide */oneway interface IMessenger {    void send (in Message msg);}
There is only one method internally for sending messages. It's more confirmed here, MessengerThe bottom is actually aidl! For information on how to implement a aidl, refer to the aidl of Android IPC.

When sending a message, call Messenger 's Send () method,

    public void Send (Message message) throws RemoteException {        mtarget.send (message);    }
Called the Mtarget. Send ()method, while Mtarget isMessengerimpl。 From the above, we can know Messengerimpl classImplements the Send () method, which sends a message to see if it actually passes through the handler sends a message. About handler sending messages,can refer to the Android source code parsing handler processing mechanism (ii).

The server has a Onbind () method that returns a IBinder object from Messenger,

    Public IBinder Onbind (Intent Intent) {        return messenger.getbinder ();    }

Keep going,

    Public IBinder Getbinder () {        return mtarget.asbinder ();    }    
Returns the Asbinder () of the Mtarget object, and what is "Mtarget.asbinder ()"?
Let's take a look at the Asbinder () method in AAPT auto-generated Aidl class when using Aidl,
@Override public Android.os.IBinder Asbinder () {return this;}
The method returns the self, which is xxxx. Stub class. Then we look at this time Mtarget object, Mtarget is Messengerimpl, and Messengerimpl is inherited from Imessenger.stub, then Mtarget.asbinder () The return is Messenger.Stub.asBinder (), while Messenger.Stub.asBinder () Return is Messenger.stub, and Messengerimpl is inherited from Imessenger.stub, so around a circle, "Mtarget.asbinder ()" Returns the Messengerimpl object itself.。 Other words "Mtarget.asbinder ()" Returns the Messengerimpl object in the current messenger.

When on the server side,"Mtarget.asbinder ()" returns the server-side Messengerimpl object, which is used to send messages to the server, while on the client,"Mtarget.asbinder ()" Returns the client's Messengerimpl object, which is used to send a message to the client.

After a client-bound remote connection succeeds, it acquires a remote IBinder object that, through the IBinder object, can obtain the Messenger object on the server, invoking the following method,

    Public Messenger (IBinder target) {        Mtarget = IMessenger.Stub.asInterface (target);    }

This is not the same as the aidl of the wording! Here is the code for AIDL,

Remote Connection    PRIVATE Serviceconnection conn = new Serviceconnection () {        @Override public        void onserviceconnected (componentname name, IBinder service) {            calculateaidl = CalculateAidl.Stub.asInterface (service);            isbindsuccess=true;        }        @Override public        void onservicedisconnected (componentname name) {            calculateaidl = null;            Isbindsuccess=false;        }    };

Nothing much! For more information on Aidl, see the Aidl of Android IPC.

Okay, so much for the source analysis of Messenger!

Iv. Summary.

The bottom of the 1.Messenger is still used aidl;

2. Server and client communication, to the server to discover the message, using the service side of Messenger (the object from the remote connection was successfully obtained through IBinder), to send a message to the client, Using Messenger from the client (the object is the parameter carried by the-replyto attribute carried in the message sent to the server);

3. In IPC, to pass parameters, you need to implement the Parcelable interface, it is recommended to use bundle encapsulation parameters.

4.Messenger will put all service requests into the queue, so it does not support multithreaded communication. If you want to support multi-threading, then please use Aidl.

Talking about the messenger of Android IPC

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.