跨进程消息处理机制
概述
之前我们讨论过在多个线程间传递消息时,使用Message-Handler机制来传递消息。而这种消息机制 在跨进程通信中同样可行,这里需要使用到一个额外的类:Messenger。 Messenger称为信使,它是Handler对象的引用。该类允许跨进程间基于Message的通信(即两个进程间 可以通过Message进行通信),在服务端使用Handler创建一个Messenger,客户端持有这个Messenger就可以 与服务端通信了。
Messenger如何跨进程发送Message?
- Messenger能够发送Message对象,它首先需要持有一个Handler对象,该对象是由处理消息的那个进程所产生的。因此Messenger的构造方法需要传入一个Handler对象。
-
Messenger还提供一个以IBinder为参数的构造方法,该方法由客户端获取了IBinder对象后还原远程的服务端Messenger,参见后面的分析。
public final class Messenger implements Parcelable { // 这里是一个IMessenger的接口,该接口由AIDL实现远程访问功能。 private final IMessenger mTarget; public Messenger(Handler target) { mTarget = target.getIMessenger(); } public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); } // ...... }
-
如何做到跨进程通信,答案是Binder机制。Messenger内部包含一个IMessenger接口,而该接口通过Handler.getIMessenger()方法获取。
public class Handler { // ...... final IMessenger getIMessenger() { synchronized (mQueue) { if (mMessenger != null) { return mMessenger; } mMessenger = new MessengerImpl(); return mMessenger; } } // 实现了IMessenger.Stub的内部类,实际则调用本地的Handler处理消息 private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { Handler.this.sendMessage(msg); } } // ...... }
服务进程如何创建Messenger?
- 服务进程创建Messenger的方法非常简单,只要将本进程的Handler对象作为参数构造一个Messenger即可。
-
通常客户端是通过BindService的形式连接到客户端,因此,服务端需要提供一个IBinder对象给客户端,Messenger.getBinder()正好提供了这个方法。
Messenger mMessenger = new Messenger(mHandler); public IBinder onBind(Intent intent) { //返回服务端信使的binder,以供客户端通过这个binder得到服务端的信使对象。 return mMessenger.getBinder(); }
客户端如何获取Messenger?
-
客户端在BindService之后,通过一个IBinder对象来构造Messenger。
public void onServiceConnected(ComponentName name, IBinder service) { // 通过IBinder构造Messenger serverMessenger = new Messenger(service); }
客户端如何传递Message?
-
客户端在重新构造了一个Messenger对象后,即可通过send方法向服务端发送消息,并且该消息是可以跨进程的。
private void sendMessage() { Message message = Message.obtain(null, MessengerService.MSG_SET_VALUE); try { // 通过send发送消息 serverMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } }
服务端如何传递Message?
- 客户端通过BindService获取到服务端的Messenger,这个过程是单向的。服务端如果需要发送消息给客户端,同样需要得到客户端的Messenger。
-
客户端在发送消息给服务端时,可以将自己的Messenger通过Message传递给服务端。
private void sendMessage() { Message message = Message.obtain(null, MessengerService.MSG_SET_VALUE); // 客户端将自己的Messenger包裹在Message中传递给服务端 message.replyTo = clientMessenger; try { // 通过send发送消息 serverMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } }