我们直接看源码:
/**
* 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的关系需要深刻理解!