Android inter-process communication-the use and understanding of Messenger

Introduction to Messenger

Messenger is based on the Message object for cross-process communication, similar to the usage of Handler sending messages to achieve inter-thread communication.

Messenger use

Let's write an example where the client sends a message to the server across processes, and the server receives an immediate reply.

Server

Implementation process

  1. First create a Handler object
  2. Then create a Messenger object, and pass the Handler object into Messenger as a parameter
  3. Finally, get the Binder object through mmessenger.getBinder and return it in the onBind method.
public class MessengerService extends Service {

    private static final String TAG = "MessengerService";
    public MessengerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }

    private MessengerHandler mHandler=new MessengerHandler();

    private Messenger mMessenger=new Messenger(mHandler);

    private static class MessengerHandler extends Handler{

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //取出客户端的消息内容
            Bundle bundle = msg.getData();
            String clientMsg = bundle.getString("client");
            Log.i(TAG,"来自客户端的消息:"+clientMsg);
            //新建一个Message对象,作为回复客户端的对象
            Message message = Message.obtain();
            Bundle bundle1 = new Bundle();
            bundle1.putString("service","今天就不去了,还有很多东西要学!!");
            message.setData(bundle1);
            try {
                msg.replyTo.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
}

Receiving messages from the client is actually the same as the communication between threads. It is also received in the handleMessage method; if the server needs to reply to the client, it needs to get the Messenger object (ie msg.replyTo ) carried by the client through msg.replyTo The .send method sends information to the client.

Client

public class MessengerActivity extends AppCompatActivity{

    private static final String TAG = "MessengerActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenger);

    }


    public void onClick(View view) {
        switch (view.getId()){
            case R.id.bindService:
                Intent intent = new Intent(this,MessengerService.class);
                bindService(intent,mConnection,BIND_AUTO_CREATE);
                break;
            case R.id.unbindService:
                unbindService(mConnection);
                break;
        }
    }



    private ServiceConnection mConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //获取服务端关联的Messenger对象
            Messenger mService=new Messenger(service);
            //创建Message对象
            Message message = Message.obtain();
            Bundle bundle = new Bundle();
            bundle.putString("client","今天出去玩吗?");
            message.setData(bundle);
            //在message中添加一个回复mRelyMessenger对象
            message.replyTo=mRelyMessenger;
            try {
                mService.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

    private GetRelyHandler mGetRelyHandler=new GetRelyHandler();

    private Messenger mRelyMessenger=new Messenger(mGetRelyHandler);
    public static class  GetRelyHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Bundle bundle = msg.getData();
            String serviceMsg = bundle.getString("service");
            Log.i(TAG, "来自服务端的回复:"+serviceMsg);

        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

    }

}

After binding the service, the client obtains the Messenger object (mService) through IBinder in the ServiceConnection, and then uses the send method of mService to send the Message as a formal parameter to the client. If the server receives a message and needs to reply to the client, it also needs to create a Handler object first, then create a Messenger object (mRelyMessenger) and pass the Handler into it, and finally in the onServiceConnected method, assign the mRelyMessenger object to message.replyTo, The process is similar to that of the server.

Note that
msg.replyTo in the client and server are actually the same object
. The first message sent by the client is Message (mService)
sent and the message sent by the server is sent by msg.replyTo.

Registration documents

<service
            android:name=".messenger.MessengerService"
            android:enabled="true"
            android:exported="true"
            android:process=":remote">
        </service>

operation result

First, the server receives the message from the client, and then the client receives the reply from the server.

Message accepted by the server:

Write picture description here

The client accepts the reply message from the server:
Write picture description here

Messenger understanding

First understand the return value of onBind in the server, the mmessenger.getBinder() method

@Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }

Source code of getBinder method

  /**
     * Retrieve the IBinder that this Messenger is using to communicate with
     * its associated Handler.
     * 
     * @return Returns the IBinder backing this Messenger.
     */
    public IBinder getBinder() {
        return mTarget.asBinder();
    }

From the source code, you can get the IBinder object associated with Messenger through the mTarget object. This is the return value required by the onBind method in the Service. Then let's see how mTarget comes from.

  private final IMessenger mTarget;

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

Isn’t this the construction method for us to create the member variable mmessenger, yes it is the new Messenger(mHandler) , and then the implementation of the getIMessenger method

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);
    }
}

In fact, the return value of getIMessenger is an instance of MessengerImpl, which means that mTarget is the MessengerImpl object, and MessengerImpl is inherited from IMessenger.Stub. See if this is a bit like the java class generated by the aidl file, yes it is the file generated by the aidl Just look at the source code.

public interface IMessenger extends android.os.IInterface {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements
            android.os.IMessenger {
        private static final java.lang.String DESCRIPTOR = "android.os.IMessenger";

        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        public static android.os.IMessenger asInterface(...}

        public android.os.IBinder asBinder() {
            return this;
        }

        @Override
        public boolean onTransact(int code, android.os.Parcel data,
                android.os.Parcel reply, int flags)
                throws android.os.RemoteException {...}

        private static class Proxy implements android.os.IMessenger {...}

    public void send(android.os.Message msg)
            throws android.os.RemoteException;
}

At this point, I understand why the Binder object can be obtained by the mMessenger.getBinder() method. In the end, it is completed by the AIDL file, but Messenger has deeply encapsulated the AIDL, which is easier to use.

Client The
client is actually nothing, it's the same as usual, first get the service (Ibinder) object through onServiceConnected, but the way to get it is different

Messenger mService=new Messenger(service);

The source code is as follows:

public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }

The java class generated by this aidl is the same, IMessenger.Stub is a Binder object, and the related public interface IMessenger instance is obtained through Binder.

to sum up

Write picture description here

Compared with AIDL, the use of Messenger is very simple, saving a lot of tedious operations in the middle. Encapsulation of AIDL, that is, encapsulation of Binder, is one of the lower cost of inter-process communication.

reference

  • Android development art exploration
  • https://blog.csdn.net/lmj623565791/article/details/47017485
  • https://www.jianshu.com/p/af8991c83fcb
  • https://blog.csdn.net/u011240877/article/details/72836178

Guess you like

Origin blog.csdn.net/hzw2017/article/details/81090319