1. Differences between Messenger and AIDL

  • When it comes to interprocess communication, Messenger is easier to implement than AIDL, and it doesn’t need to implement the AIDL interface
  • Supports callbacks, which can interact with the client
  • Messenger queues all service calls, while the pure AIDL interface sends multiple requests to the service at the same time, which then has to deal with multi-threading.
  • For most applications, the service does not need to perform multithreading, so using Messenger lets the service handle one call at a time.
  • But if your service must perform multithreading, you should use AIDL to define the interface.

2. How to use Messenger for inter-process communication

  1. The service implements a Handler that receives callbacks from each invocation of the client
  2. Handler is used to create Messenger objects (a reference to Handler)
  3. Messenger creates an IBinder and the service returns it to the client via onBind()
  4. The client instantiates Messenger (the Handler that references the service) using IBinder, which then sends the Message object to the service. Create a new clientMessenger instantiation locally (referring to a newly created Handler locally) and set it to clientMessenger using the message. replyto method when sending objects to the service so that the server can communicate with the client.
  5. The service receives each Message in its Handler (specifically, in the handleMessage() method), takes the Messenger instance of the client via msg.replyto, and interacts with the client through that Messenger.

3. Example of using Messenger

  1. Create a server APK and create the service class MessengerService

    public class MessengerService extends Service {
     /** Command to the service to display a message */
     static final int MSG_SAY_HELLO = 1;
     static final int MSG_SAY_HELLO_TO_CLIENT = 2;
     private static final String TAG = "MessengerService";
    
     /** get Messenger from client **/
     private Messenger clientMessenger;
     /**
      * Handler of incoming messages from clients.
      */
     class IncomingHandler extends Handler {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_SAY_HELLO:
                     Log.i(TAG, "handleMessage: "+"Server receives message from client");
                     Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
                     clientMessenger = msg.replyTo;
                     if(clientMessenger != null){
                         Message msgToClient = Message.obtain();
                         msgToClient.what = MSG_SAY_HELLO_TO_CLIENT;
                         try {
                             clientMessenger.send(msgToClient);
                         } catch (RemoteException e) {
                             e.printStackTrace();
                         }
                     }
                     break;
                 default:
                     super.handleMessage(msg);
             }
         }
     }
    
     /**
      * Target we publish for clients to send messages to IncomingHandler.
      */
     final Messenger mMessenger = new Messenger(new IncomingHandler());
    
     /**
      * When binding to the service, we return an interface to our messenger
      * for sending messages to the service.
      */
     @Override
     public IBinder onBind(Intent intent) {
         Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
         returnmMessenger.getBinder(); }}Copy the code

    2. Create a client APK and create a client ClientActivity

public class ClientActivity extends Activity {
    @BindView(R.id.messenger_test)
    Button messengerBtn;
    private static final int MSG_SAY_HELLO = 1;
    private static final int MSG_SAY_HELLO_TO_CLIENT = 2;
    /** Messenger for communicating with the service. */
        Messenger mService = null;
        /** Flag indicating whether we have called bind on the service. */
        private Messenger clientMessenger = new Messenger(new ClientHandler());


        private class ClientHandler extends Handler {
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == MSG_SAY_HELLO_TO_CLIENT) {
                    Log.i("ClientActivity"."Client receives message from Service:");
                }
            }
        }


    boolean mBound;

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.

            mService = new Messenger(service);
            mBound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            mService = null;
            mBound = false; }}; public voidsayHello() {
        if(! mBound)return;
        // Create and send a message to the service, using a supported 'what' value
        Message msg = Message.obtain(null, MSG_SAY_HELLO, 0, 0);
        msg.replyTo = clientMessenger;
        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        ButterKnife.bind(this);

        messengerBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Bind to the service sayHello(); }}); } @Override protected voidonStart() {
        super.onStart();
        bindService(new Intent("com.installer.ServerService"), mConnection,
                Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false; }}}Copy the code