今天我们来聊一聊Android中另外一种IPC机制-Messenger,可以理解成信使,通过它可以在不同的进程中传递Message对象,其实它的底层实现还是AIDL,为什么这么说?先卖个关子,继续往后看就知道了。我们先看下Messenger怎么使用。还是通过一个栗子来说明,客户端向服务端发起请求,服务端返回一个百度的url,客户端再进行加载,就是这么简单。
当然在这之前有点AIDL的知识看起来会比较轻松,可以参考我前面的AIDL的博客:http://www.jianshu.com/p/4ebd4783d3d9
Messenger基本使用
当然还是分成服务端进程和服务端进程
服务端进程
首先创建一个Service来处理客户端的连接请求,创建一个Messenger,在onBind中返回这个Messenger对象底层的Binder给客户端即可。
通过Handler来创建Messenger,在收到客户端发过来的请求时会回送一个msg:clientMessenger.send(response);
private Messenger messenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
try {
Thread.sleep(5 * 1000); //模拟耗时
} catch (Exception e) {
e.printStackTrace();
}
Message response = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString("body", REMOTE_URL);
response.setData(bundle);
Messenger clientMessenger = msg.replyTo;
try {
clientMessenger.send(response);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
客户端需要在清单中进行注册,在另外一个juexingzhe进程
<service android:name=".MessengerService" android:process=":juexingzhe"/>
在客户端绑定服务的时候返回这个Messenger对象。
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
客户端进程
客户端首先发起绑定服务的请求,在服务绑定成功后,通过服务端返回的IBinder对象就可以创建一个Messenger mSender,通过它就可以向服务端发送信息了。
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mSender = new Messenger(iBinder);
sendMessage();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
客户端还需要创建一个Handler,通过Handler来创建一个Messenger,用来接收服务端发送的消息:
private Messenger mReceiver = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i(TAG, "msg is received from service");
Bundle data = msg.getData();
if (null != data) {
mButton.setVisibility(View.GONE);
String body = data.getString("body");
mWebView.loadUrl(body);
}
}
});
Messenger源码分析
使用还是比较简单的,基本和Handler的用法比较类似。我们下面来扒一扒源码。
1.构造
我们在上面的例子中用到了两个Messenger的构造函数:
一个是在服务绑定成功后mSender = new Messenger(iBinder);
另外一个是在创建的时候private Messenger mReceiver = new Messenger(new Handler())
我们先看下通过Binder的构造函数,可以看见浓浓的AIDL的味道吧。在夸进程通信的情况下,通过asInterface会将返回服务端Binder的代理Proxy。
/**
* 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);
}
我们再看下通过Handler的构造函数,只有一行代码,就是获取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();
}
上面两个构造函数无一例外都是获得mTarget对象,它是一个IMessenger对象
private final IMessenger mTarget;
IMessenger就是Android系统帮我们定义在android.os包下的一个AIDL接口,编译后会生成IMessenger.java文件。
package android.os;
import android.os.Message;
oneway interface IMessenger{
void send(in Message msg);
}
因此mTarget有两种情况,一种是通过Handler或的IMessenger:
mTarget = Handler.getIMessenger();
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) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
一种是通过IBinder转化得到的IMessenger:
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
public static android.os.IMessenger asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin =obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof android.os.IMessenger))) {
return ((android.os.IMessenger) iin);
}
return new android.os.IMessenger.Stub.Proxy(obj);
}
2.发送消息
Messenger发送消息的源码,都是通过mTarget进行发送。
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
发送消息要分成两种情况:
给服务端发送消息
一种是客户端给服务端发送消息(这种情况的Messenger是客户端通过服务端返回的IBinder进行构造),
private void sendMessage() {
if (null != mSender) {
Message msg = Message.obtain();
msg.replyTo = mReceiver;
mSender.send(msg);
}
}
这种情况下会的调用流程会是这样的(注意前方高能,可能会引起轻微不适):
Proxy.send()--->mRemote.transact(Stub.TRANSACTION_send, _data, null, android.os.IBinder.FLAG_ONEWAY)--->Stub.onTransact--->this.send(_arg0)(这里面的arg0就是msg)--->Handler中MessengerImpl.send()--->handler.sendMessage--->服务端handleMessage
上面这个过程会比较绕:
1.因为和服务端通信是跨进程,所以首先会在Proxy中序列化msg参数(包括bundle和Messenger),然后会调用到服务端进程的onTransact;
2.在服务端进程中会调用this.send,那这边的this指的是哪个对象?还记得服务端Messenger是怎么创建的吗?也是通过Handler创建的,因此this.send就会调用服务端Messenger的Handler中内部类MessengerImpl中的send方法;
3.MessengerImpl中的send方法会调用Handler的sendMessage方法
Handler.this.sendMessage(msg);
明显这里的Handler就是服务端构建Messenger我们传进去的handler,因此msg也就被handleMessage处理。
给客户端发送消息
这种情况下会拿到客户端发送过来的Messenger,那么为什么服务端可以直接拿到Messenger就给客户端发送消息,不是应该先拿到一个客户端的Binder,然后再转化balabalabalabala吗?
Messenger clientMessenger = msg.replyTo;
clientMessenger.send(response);
其实Android也是这样做的,我们去一探究竟(注:下方源码是我经过删减的):
在客户端send消息给服务端时会,在Proxy的send方法中会将msg和clientMessenger一起会调用Message msg.writeToParcel(_data, 0)写到data中;
public void send(android.os.Message msg) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
_data.writeInterfaceToken(DESCRIPTOR);
if ((msg != null)) {
_data.writeInt(1);
msg.writeToParcel(_data, 0);
}
}
在Message的writeToParcel方法中会调用writeMessengerOrNullToParcel,然后在方法中会在data中writeStrongBinder,会将clientMessenger的Binder存储起来,是不是恍然大悟???
Messenger.writeMessengerOrNullToParcel(replyTo, dest);
dest.writeInt(sendingUid);
public static void writeMessengerOrNullToParcel(Messenger messenger, Parcel out) {
out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder(): null);
}
接下来就顺利成章了,服务端会在onTransact中调用CREATOR;
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_send: {
data.enforceInterface(DESCRIPTOR);
android.os.Message _arg0;
if ((0 != data.readInt())) {
_arg0 = android.os.Message.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.send(_arg0);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
public static final Parcelable.Creator<Message> CREATOR
= new Parcelable.Creator<Message>() {
public Message createFromParcel(Parcel source) {
Message msg = Message.obtain();
msg.readFromParcel(source);
return msg;
}
public Message[] newArray(int size) {
return new Message[size];
}
};
然后会调用Message的readFromParcel,接着就是readMessengerOrNullFromParcel,在该方法中会得到clientMessenger
private void readFromParcel(Parcel source) {
replyTo = Messenger.readMessengerOrNullFromParcel(source);
sendingUid = source.readInt();
}
public static Messenger readMessengerOrNullFromParcel(Parcel in) {
IBinder b = in.readStrongBinder();
return b != null ? new Messenger(b) : null;
}
可以看到服务端发送消息也是通过Binder,之后过程就与客户端发送消息服务端一样了,就不做分析了。
其他
因为Messenger在进程内是通过Handler进行消息发送和处理的,所以只能串行发送消息和处理消息;
Messenger跨进程调用方法是非阻塞的,这个在我们栗子中可以体现,客户端发送消息后会马上打印后面的log,一段时间后服务端才返回消息。还记得IMessenger.aidl这个文件?有oneway这个关键字,这个就是非阻塞的原因,具体可以看后面参考链接中的博客。
private void sendMessage() {
mSender.send(msg);
Log.i(TAG, "msg is right now send");
}
private Messenger mReceiver = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i(TAG, "msg is received from service");
}
});
Messenger其实就是Android帮我们封装好的AIDL,用法和Handler类似,比较方便,文中的代码可以在Github中看到:https://github.com/juexingzhe/MessengerSample
好了,我们今天的Messenger之旅就到此结束了。谢谢!
参考链接:
http://www.jianshu.com/p/c6a73b9a14ce
http://www.jianshu.com/p/4ebd4783d3d9
欢迎关注公众号:JueCode