我们直接看源码:
/** * Reference to a Handler, which others can use to send messages to it. * This allows for the implementation of message-based communication across * processes, by creating a Messenger pointing to a Handler in one process, * and handing that Messenger to another process. */ public final class Messenger implements Parcelable { private final IMessenger mTarget; /** * Create a new Messenger pointing to the given Handler. Any Message * objects sent through this Messenger will appear in the Handler as if * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had * been called directly. * * @param target The Handler that will receive sent messages. */ public Messenger(Handler target) { mTarget = target.getIMessenger(); }Messenger,信使,其指向一个Handler,他人可以使用信使向Handler发送消息。信使实现了基于消息队列的跨进程的通讯,在一个进程中创建一个指向Handler的信使,然后把信使返回给其他的进程,使得其它的进程可以向这个进程发送消息。在Messenger内部有一个IMessenger接口指针,其在Messenger的构造函数中指向了一个Handler中的IMessenger,这样就保存了一个指向Handler的指针。
我们再来看一下Handler是怎么返回一个IMessenger接口的实现的:
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) { Handler.this.sendMessage(msg); } }我们看到在getIMessenger方法内部对消息队列进行加锁,是为了确保一个消息队列只有一个信使,这个有点类似实现单例时也要加锁一样。IMessenger接口指向一个私有内部类MessengerImpl,其 send方法内部使用Handler.this.sendMessage方法。
/** * Send a Message to this Messenger's Handler. * * @param message The Message to send. Usually retrieved through * {@link Message#obtain() Message.obtain()}. * * @throws RemoteException Throws DeadObjectException if the target * Handler no longer exists. */ public void send(Message message) throws RemoteException { mTarget.send(message); }再来看Messenger中的send方法,其调用IMessenger接口的send方法,所以最终是调用了Handler中的sendMessage方法。
从一个作为服务器的Service中返回一个Messenger给调用的客户端是怎么做到的呢?
/** * 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(); }看Android developer官网关于 Messenger的例子
在一个客户端绑定到一个服务器的时候,我们返回Messenger.getBinder()的结果。其实现如下:
/** * 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(); }其中的mTarget就是IMessenger接口的asBinder()方法,其实际调用 IMessenger.Stub.asBinder方法。
在一个客户端与服务器进行连接的时候,其会建立对Messenger的引用:
public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service. We are communicating with our // service through an IDL interface, so get a client-side // representation of that from the raw service object. mService = new Messenger(service); mCallbackText.setText("Attached."); // We want to monitor the service for as long as we are // connected to it. try { Message msg = Message.obtain(null, MessengerService.MSG_REGISTER_CLIENT); msg.replyTo = mMessenger; mService.send(msg); // Give it some value as an example. msg = Message.obtain(null, MessengerService.MSG_SET_VALUE, this.hashCode(), 0); mService.send(msg); } catch (RemoteException e) { // In this case the service has crashed before we could even // do anything with it; we can count on soon being // disconnected (and then reconnected if it can be restarted) // so there is no need to do anything here. } // As part of the sample, tell the user what happened. Toast.makeText(Binding.this, R.string.remote_service_connected, Toast.LENGTH_SHORT).show(); }其调用Messenger另一个构造方法:
/** * Create a Messenger from a raw IBinder, which had previously been * retrieved with {@link #getBinder}. * * @param target The IBinder this Messenger should communicate with. */ public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }把IBinder接口转化为IMessenger接口,这样就在客户端的代码中引用了服务器的Messenger,之后就是想向服务器发什么消息就发什么消息了。
那么服务器怎么向客户端发消息呢?总不能只有客户端发命令给服务器吧。双向通讯才是关键。
Message msg = Message.obtain(null, MessengerService.MSG_REGISTER_CLIENT); msg.replyTo = mMessenger; mService.send(msg);一个客户端向服务器发送的消息里面指定了msg.replayTo=mMessenger;
/** * Optional Messenger where replies to this message can be sent. The * semantics of exactly how this is used are up to the sender and * receiver. */ public Messenger replyTo;一条消息可以指定是由哪个信使来发出的,这样在Handler中收到消息之后就可以调用其引用的信使来发送消息。
/** * Handler of incoming messages from clients. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_REGISTER_CLIENT: mClients.add(msg.replyTo); break; case MSG_UNREGISTER_CLIENT: mClients.remove(msg.replyTo); break; case MSG_SET_VALUE: mValue = msg.arg1; for (int i = mClients.size() - 1; i >= 0; i--) { try { mClients.get(i).send( Message.obtain(null, MSG_SET_VALUE, mValue, 0)); } catch (RemoteException e) { // The client is dead. Remove it from the list; // we are going through the list from back to front // so this is safe to do inside the loop. mClients.remove(i); } } break; default: super.handleMessage(msg); } } }例如,在上面这个服务器的Handler中收到自己的信使发送的消息之后,把消息中引用的客户端的信使的引用保存到一个集合中,这样就拿到客户端的信使,只要调用其的send方法就可以调用客户端的代码。如此实现了双向通信。
这样一来,服务器可以实现广播、组播、单播消息的功能。
Messenger的接口IMessenger实际是通过AIDL来做的。
文件位于:frameworks/base/core/java/android/os/IMessenger.aidl
看来Handler不仅仅能够用于线程之间的通讯还能用于进程之间的通讯!Handler,Looper,MessageQueue,Message的关系需要深刻理解!