Eleven, Android in the way of IPC (3) --- use Messenger

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/yz_cfm/article/details/90416381

    Messenger is a lightweight Android in the IPC program. It can be translated as messenger, is a class of Android, it can be passed between different processes Message object, into the data we need to pass in the Message, you can easily achieve inter-process data passed. Let's look at the source Messenger class:

/*
* 可以看到 Messenger 实现了 Parcelable 接口,所以它可以在进程间进行传递。
*/
public final class Messenger implements Parcelable {
    private final IMessenger mTarget;

    /**
     * Messenger 的构造方法,创建一个与目标 Handler 关联的 Messenger 对象。
     */
    public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }

    /**
     * 发送一个 Message 对象给这个 Messenger 的 Handler,然后由该 Handler 来处理消息。
     */
    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }

    /**
     * 返回与该 Messenger 相关的 IBinder 对象。
     */
    public IBinder getBinder() {
        return mTarget.asBinder();
    }

    /**
     * 通过参数中的 IBinder 对象创建一个与之相关联的 Messenger 对象。
     */
    public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }
}

    By IMessenger objects in the source code and IMessenger.asBinder (), IMessenger.Stub.asInterface () method can be seen, in fact, the underlying implementation is AIDL Messenger, it's just AIDL the package, so that we are very simple to use. At the same time, because it handles only one request, so the server does not exist in the case of concurrent execution, so we do not consider the issue of the server thread synchronization.

    The following look at its use:

eg1: The client sends to the server an integer of two int type, and the server requests the calculation results of two integers, but the server does not return the results to the client, performs computation logic only.

Remote server MessengerService.java:

package com.cfm.messengertest;

/**
* 步骤1. 在服务端创建一个 Service 来处理客户端的连接请求
*/
public class MessengerService extends Service {
    private static final String TAG = "cfmtest";

    /**
     * 步骤2. 创建一个执行客户端的请求的 Handler 类
     */
    private static class MessengerHandler extends Handler {

        // 执行客户端请求的回调方法
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case ClientActivity.MSG_FROM_CLIENT:
                    Log.d(TAG, "接收到了客户端发起的请求!");
                    int result = msg.getData().getInt("a") + msg.getData().getInt("b");
                    Log.d(TAG, "服务端计算两个数相加的结果为:" + result);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * 步骤3: 通过步骤 2 创建一个 Handler 对象,然后创建一个与之相关联的 Messenger
     */
    private final Messenger mMessenger = new Messenger(new MessengerHandler());

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "远程服务绑定成功!");

        /**
         *  步骤4: 获取该 Messenger 对象的底层 Binder,然后通过 Binder 完成进程间通信。
         */
        return mMessenger.getBinder();
    }
}

Client ClientActivity.java:

package com.cfm.messengertest;

/**
*  客户端需要绑定远程服务,然后根据服务端返回的 IBinder 对象创建 Messenger 对象并使用此对象向服务端发送消息即可完成进程间通信。
*/
public class ClientActivity extends AppCompatActivity {
    
    private static final String TAG = "cfmtest";
    public static final int MSG_FROM_CLIENT = 1;
    private Messenger mMessenger;
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 根据服务端返回的 IBinder ,创建一个 Messenger 对象
            mMessenger = new Messenger(service);

            // 通过该 Messenger 对象,发送 Message 消息给服务端,服务端即可根据 Message 的信息作相应的处理
            Message msg = Message.obtain();
            msg.what = MSG_FROM_CLIENT;
            Bundle bundle = new Bundle();
            bundle.putInt("a", 333);
            bundle.putInt("b", 555);
            msg.setData(bundle);

            Log.d(TAG, "客户端请求服务端计算 333 和 555 相加的结果!");
            try {
                mMessenger.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

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

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

        // 绑定远程服务
        Intent intent = new Intent(this, MessengerService.class);
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }
}

AndroidManifest.xml:

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

Print Log Information:

Client:

com.cfm.messengertest D/cfmtest: 客户端请求服务端计算 333 和 555 相加的结果!

Server:

com.cfm.messengertest:remote D/cfmtest: 远程服务绑定成功!
com.cfm.messengertest:remote D/cfmtest: 接收到了客户端发起的请求!
com.cfm.messengertest:remote D/cfmtest: 服务端计算两个数相加的结果为:888

 

    The above can be derived by way of example:

    1. Data transmission in Messenger data must be placed in Message, because the Messenger and Message have achieved Parcelable interface, so they can be transmitted across processes. Therefore, the data types supported Message Messenger is the supported data transfer type.

    2. Message can be used in the vector comprises what, arg1, agr2, Bundle and replyTo.

    Another field object 3. Message is very useful in the same process, but at the time of inter-process communication, and in Android 2.2 before the object field does not support cross-transmission process, after 2.2 supports only system-supplied and implemented Parcelable Interface the objects can be transmitted through it. So we realized Parcelable custom object interface can not be transmitted through the object field, but we can be achieved by Bundle object.

 

eg2: The client sends to the server an integer of two int type, and the server requests the calculation results of two integers, then the result will be the server back to the client computing.

Remote server MessengerService.java:

package com.cfm.messengertest;

/**
* 步骤1. 在服务端创建一个 Service 来处理客户端的连接请求
*/
public class MessengerService extends Service {
    private static final String TAG = "cfmtest";
    public static final int MSG_FROM_SERVER = 2;

    /**
     * 步骤2. 创建一个执行客户端的请求的 Handler 类
     */
    private static class MessengerHandler extends Handler {

        // 执行客户端请求的回调方法
        @Override
        public void handleMessage(Message msg) {

            switch (msg.what) {
                case ClientActivity.MSG_FROM_CLIENT:
                    Log.d(TAG, "接收到了客户端发起的请求!");

                    // 获取客户端发过来的 Messenger 对象,然后通过该对象向客户端回复消息
                    // 此时与这个 messenger 相关联的 handler 就是客户端的 handler
                    Messenger messenger = msg.replyTo;
                    int result = msg.getData().getInt("a") + msg.getData().getInt("b");
                    Bundle bundle = new Bundle();
                    bundle.putInt("result", result);
                    Message replyMsg = Message.obtain(null, MSG_FROM_SERVER);
                    replyMsg.setData(bundle);

                    try {
                        messenger.send(replyMsg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * 步骤3: 通过步骤 2 创建一个 Handler 对象,然后创建一个与之相关联的 Messenger
     */
    private final Messenger mMessenger = new Messenger(new MessengerHandler());

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "远程服务绑定成功!");

        /**
         *  步骤4: 获取该 Messenger 对象的底层 Binder,然后通过 Binder 完成进程间通信。
         */
        return mMessenger.getBinder();
    }
}

Client ClientActivity.java:

package com.cfm.messengertest;

/**
* 客户端需要绑定远程服务,然后根据服务端返回的 IBinder 对象创建 Messenger 对象并使用此对象向服务端发送消息即可完成进程间通信。
*/
public class ClientActivity extends AppCompatActivity {

    private static final String TAG = "cfmtest";
    public static final int MSG_FROM_CLIENT = 1;

    private Messenger mMessenger;

    /**
     * 创建一个处理服务端回复的 Handler,在客户端作相应的逻辑处理。
     */
    private static class MessengerHandlerForClient extends Handler {

        @Override
        public void handleMessage(Message msg) {

            switch (msg.what) {
                case MessengerService.MSG_FROM_SERVER:
                    // 处理服务端回复的请求
                    int result = msg.getData().getInt("result");
                    Log.d("cfmtest", "客户端接收到服务端返回的计算结果: " + result);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     *  创建一个与客户端 Handler 相关联的 Messenger 对象
     */
    private Messenger mClientReplyMessenger = new Messenger(new MessengerHandlerForClient());

    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            // 根据服务端返回的 IBinder ,创建一个 Messenger 对象
            mMessenger = new Messenger(service);

            // 通过该 Messenger 对象,发送 Message 消息给服务端,服务端即可根据 Message 的信息作相应的处理
            Message msg = Message.obtain();
            msg.what = MSG_FROM_CLIENT;
            Bundle bundle = new Bundle();
            bundle.putInt("a", 333);
            bundle.putInt("b", 555);
            msg.setData(bundle);
            Log.d(TAG, "客户端请求服务端计算 333 和 555 相加的结果!");
            // 服务端可以获取到该 Messenger 对象,然后通过该对象向客户端发送消息
            msg.replyTo = mClientReplyMessenger;
            try {
                mMessenger.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

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

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

        // 绑定远程服务
        Intent intent = new Intent(this, MessengerService.class);
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }
}

AndroidManifest.xml:

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

Print Log Information:

Client:

com.cfm.messengertest D/cfmtest: 客户端请求服务端计算 333 和 555 相加的结果!
com.cfm.messengertest D/cfmtest: 客户端接收到服务端返回的计算结果: 888

Server:

com.cfm.messengertest:remote D/cfmtest: 远程服务绑定成功!
com.cfm.messengertest:remote D/cfmtest: 接收到了客户端发起的请求!

Finally, just brother to a summary chart: Messenger works diagram

    In summary:

    It can be seen through inter-process communication function Messenger achieved in general, but many support serial communication (because it handles only one message), and support for real-time communication. But the disadvantage is that it does not handle the case of high concurrency, do not support the RPC (Remote Procedure Call Remote Procedure Call), because data is transmitted via Message, it can only transfer Bundle supported data types. Therefore, this method is applicable IPC scene is complicated by the low-to-many instant communication, no RPC needs or does not need to return the results of RPC needs.

Guess you like

Origin blog.csdn.net/yz_cfm/article/details/90416381