使用Messenger实现IPC通信

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liuyi1207164339/article/details/51685185

参考:https://developer.android.com/guide/components/bound-services.html

Messenger简介

如需让接口跨不同的进程工作,则可使用 Messenger 为服务创建接口。服务可以这种方式定义对应于不同类型 Message 对象的 Handler。此 Handler 是 Messenger 的基础,后者随后可与客户端分享一个 IBinder,从而让客户端能利用 Message 对象向服务发送命令。此外,客户端还可定义自有 Messenger,以便服务回传消息。

这是执行进程间通信 (IPC) 的最简单方法,因为 Messenger 会在单一线程中创建包含所有请求的队列,这样你就不必对服务进行线程安全设计。


与 AIDL 的比较

当你需要执行 IPC 时,为你的接口使用Messenger 要比使用 AIDL 实现它更加简单,因为 Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。

 对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果你的服务必须执行多线程处理,则应使用 AIDL 来定义接口。

Messenger底层实现就是AIDL,只是对AIDL进行了封装,更加便于使用。


使用Messenger 


服务端进程:

1、在服务中实现一个 Handler,由其接收来自客户端的每个调用的回调

2、Handler 用于创建Messenger 对象(对 Handler 的引用)

3、Messenger 创建一个 IBinder,服务通过onBind() 使其返回客户端

服务端的一般性代码如下所示:

public class MessengerServiceDemo extends Service {
    /**
     * Command to the service to display a message
     */
    public static final int MSG_FROM_CLIENT = 1;
    public static final String MSG_KEY_FROM_CLIENT = "MSG";
    private static final String TAG = MessengerServiceDemo.class.getSimpleName();

    /**
     * Handler of incoming messages from clients.
     */
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_FROM_CLIENT:
                    Log.i(TAG, "receice from client:" + msg.getData().get(MSG_KEY_FROM_CLIENT));
                    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) {
        return mMessenger.getBinder();
    }
}


然后注册Service,让其运行在不同的进程:

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

客户端进程:

客户端使用 IBinder 将 Messenger(引用服务的Handler)实例化,然后使用后者将 Message 对象发送给服务。


客户端的一般性代码如下所示:

public class MessengerActivity extends AppCompatActivity {
    Messenger mService = null;
    boolean mBound;

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

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            mService = new Messenger(service);
            mBound = true;
            Message msg = Message.obtain(null, MessengerServiceDemo.MSG_FROM_CLIENT, 0, 0);
            Bundle bundle=new Bundle();
            bundle.putString(MessengerServiceDemo.MSG_KEY_FROM_CLIENT,"hi,this is client!");
            msg.setData(bundle);
            try {
                mService.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        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;
        }
    };
    @Override
    protected void onStart() {
        super.onStart();
        bindService(new Intent(this, MessengerServiceDemo.class), mConnection,
                Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
}


运行,打印Log如下所示,说明服务端接收到了客户端发来的消息!

01-28 20:11:59.926 6112-6112/com.easyliu.demo.messengerdemo:remote I/MessengerServiceDemo: receice from client:hi,this is client!
但是此时服务端是无法往客户端回传信息的,如果需要服务端能够回复客户端,就和服务端一样,我们还需创建一个Handler并且创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端通过这个replyTo参数就可以回应客户端。


客户端代码修改如下所示:

 /**
     * 处理从服务器端发来的信息
     */
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MessengerService.MSG_FROM_SERVICE:
                    mCallbackText.setText("Received from service: " + msg.getData().get(MessengerService.MSG_KEY_FROM_SERVICE));
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            mService = new Messenger(service);
            mCallbackText.setText("Attached.");
            try {
                //发送注册消息
                Message msg = Message.obtain(null,
                        MessengerService.MSG_FROM_CLIENT);
                msg.replyTo = mMessenger;//用于服务端回传信息
                mService.send(msg);

            } catch (RemoteException e) {
            }
            // As part of the sample, tell the user what happened.
            Toast.makeText(MainActivity.this, R.string.remote_service_connected,
                    Toast.LENGTH_SHORT).show();
        }

        public void onServiceDisconnected(ComponentName className) {
            mService = null;
            mCallbackText.setText("Disconnected.");
            Toast.makeText(MainActivity.this, R.string.remote_service_disconnected,
                    Toast.LENGTH_SHORT).show();
        }
    };

服务端的代码如下,得到了客户端的Messenger之后就可以往客户端发送message了。

static final String MSG_KEY_FROM_SERVICE = "message";
    static final int MSG_FROM_CLIENT = 1;
    static final int MSG_FROM_SERVICE = 2;
    /**
     * 处理从客户端发来的消息
     */
    static class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_FROM_CLIENT:
                    Messenger client=msg.replyTo;//得到客户端的Messenger
                    Message message = Message.obtain(null,
                            MessengerService.MSG_FROM_SERVICE);
                    Bundle bundle = new Bundle();
                    bundle.putString(MessengerService.MSG_KEY_FROM_SERVICE, "I have received message!");
                    message.setData(bundle);
                    try {
                        client.send(message);//服务端回传给客户端
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

以上就是利用Messenger实现客户端和服务端的双向通信。

与 AIDL 比较

当您需要执行 IPC 时,为您的接口使用Messenger 要比使用 AIDL 实现它更加简单,因为 Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。

对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果您的服务必须执行多线程处理,则应使用 AIDL 来定义接口。

展开阅读全文

没有更多推荐了,返回首页