上一章讲了 aidl,这一章讲讲 Messenger, Messenger 是对 aidl 的封装,使用起来比较简单。我们先来看看这个类的源码
public final class Messenger implements Parcelable {
private final IMessenger mTarget;
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
public IBinder getBinder() {
return mTarget.asBinder();
}
public boolean equals(Object otherObj) {
if (otherObj == null) {
return false;
}
try {
return mTarget.asBinder().equals(((Messenger)otherObj)
.mTarget.asBinder());
} catch (ClassCastException e) {
}
return false;
}
public int hashCode() {
return mTarget.asBinder().hashCode();
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeStrongBinder(mTarget.asBinder());
}
public static final Parcelable.Creator
= new Parcelable.Creator
public Messenger createFromParcel(Parcel in) {
IBinder target = in.readStrongBinder();
return target != null ? new Messenger(target) : null;
}
public Messenger[] newArray(int size) {
return new Messenger[size];
}
};
public static void writeMessengerOrNullToParcel(Messenger messenger,
Parcel out) {
out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder()
: null);
}
public static Messenger readMessengerOrNullFromParcel(Parcel in) {
IBinder b = in.readStrongBinder();
return b != null ? new Messenger(b) : null;
}
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
}
Messenger 实现了 Parcelable 接口,可以被序列化,describeContents()、writeToParcel() 和 CREATOR 是实现的方法;Messenger 的构造方法有两个,构造参数分别为Handler 和 IBinder,相同的一点都是从 Handler 或 IBinder 中获取 IMessenger mTarget,从这里可以看出来,IMessenger 也实现了 IInterface 接口;getBinder() 方法返回的是 mTarget.asBinder(); equals(Object otherObj) 方法比较的是Messenger中包含的 IBinder; send(Message message) 方法最终调用的是 IMessenger 的 send(message) 方法; writeMessengerOrNullToParcel() 和 readMessengerOrNullFromParcel() 方法则是跨进程通讯时,序列化和反序列化时转换数据时用的。
我们先说一下用法,它是对aidl的封装,当然也是通过 bindService ,在 Service 中 接收消息和回传消息,我们写出跨进程的代码, 在同一个apk中模拟两个不同的进程
客户端 Activity
private void binderServe() {
bindService(new Intent(this, MessengerService.class),
mConnection, Context.BIND_AUTO_CREATE);
}
boolean mIsMessenger = false;
private ServiceConnection mConnection = new ServiceConnection(){
public void onServiceConnected(ComponentName className, IBinder service) {
mIsMessenger = true;
// 向远程服务发消息
Messenger messenger = new Messenger(service);
Message msg = Message.obtain(null, 1);
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName className) {
mIsMessenger = false;
}
};
@Override
protected void onStop() {
super.onStop();
// 解绑远程服务
if (mIsMessenger) {
unbindService(mConnection);
}
}
服务端 Service
public class MessengerService extends Service {
public MessengerService() {
}
final Messenger mServiceMessenger = new Messenger(new Handler(){
@Override
public void handleMessage(Message msg) {
// 接收客户端消息
switch (msg.what) {
case 1:
Log.e("messenger", "service ! ");
break;
}
}
});
@Override
public IBinder onBind(Intent intent) {
return mServiceMessenger.getBinder();
}
}
我们点击按钮,执行 binderServe() 方法,就会看到打印log日志 messenger: service ! 说明activity 发送 Message,传递给了不同进程的 Service ,Service 接收后,通过 Handler 来接收到信息,然后打印了出来。如果我们 Service 也想传递信息给 Activity ,该怎么办? Messenger 同样封装好了,我们对 Activity 稍作修改
private Messenger mMessenger = new Messenger(new Handler(){
@Override
public void handleMessage(Message msg){
// 接收远程服务消息
switch (msg.what){
case 1:
Log.e("messenger", "activity ! ");
break;
}
}
});
private ServiceConnection mConnection = new ServiceConnection(){
public void onServiceConnected(ComponentName className, IBinder service) {
mIsMessenger = true;
// 向远程服务发消息
Messenger messenger = new Messenger(service);
Message msg = Message.obtain(null, 1);
// 注意重点,在这一步,把 mMessenger 传递给 Message,当做它的一个属性
msg.replyTo = mMessenger;
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName className) {
mIsMessenger = false;
}
};
再看看 Service 端
final Messenger mServiceMessenger = new Messenger(new Handler(){
@Override
public void handleMessage(Message msg) {
// 接收客户端消息
switch (msg.what) {
case 1:
Log.e("messenger", "service ! ");
try {
// 向客户端发消息, 这里 msg.replyTo 就是 activity 中传入的对象
Messenger messenger = msg.replyTo;
messenger.send(Message.obtain(null, 1));
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
});
重复开始的操作,我们点击按钮,看一下打印的日志
E/messenger: service !
E/messenger: activity !
说明双向通讯成功。
我们知道,通过 aidl 跨进程通讯,客户端是同步的,一直处于UI线程,如果服务端有耗时操作,客户端很可能就ANR异常了,那么 Messenger 有这个问题吗?试一下
在Service中打印log日志的后面,添加一个线程睡眠
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
重复一开始的操作,打印日志
05-30 16:17:34.624 32674-32674/? E/messenger: service !
05-30 16:17:40.625 32511-32511/E/messenger: activity !
客户端没有出现ANR异常,这是怎么回事呢?还有,messenger.send(msg) 又是怎么发送信息呢? 我们还是先来看看 IMessenger 的源码
public interface IMessenger extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements android.os.IMessenger {
private static final java.lang.String DESCRIPTOR = "android.os.IMessenger";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static android.os.IMessenger asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = (android.os.IInterface) obj
.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof android.os.IMessenger))) {
return ((android.os.IMessenger) iin);
}
return new android.os.IMessenger.Stub.Proxy(obj);
}
public android.os.IBinder asBinder() {
return this;
}
@Override
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: { // 接收的code和发送的code都是TRANSACTION_send
data.enforceInterface(DESCRIPTOR);
android.os.Message _arg0;
if ((0 != data.readInt())) { // data.readInt为1(当msg不为空时)
_arg0 = android.os.Message.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.send(_arg0);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements android.os.IMessenger {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
public void send(android.os.Message msg)
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((msg != null)) {
_data.writeInt(1);
msg.writeToParcel(_data, 0);// 将msg所有字段(what,obj)写到_data中去
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_send, _data, null, // // 接收的code和发送的code都是TRANSACTION_send
android.os.IBinder.FLAG_ONEWAY);
} finally {
_data.recycle();
}
}
}
static final int TRANSACTION_send = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void send(android.os.Message msg) throws android.os.RemoteException;
}
IMessenger 果然是继承了IInterface,内部抽象类 Stub 是关键,妥妥的一个 aidl ,咱们重点看 onTransact() 方法中 case TRANSACTION_send 的代码
case TRANSACTION_send: { // 接收的code和发送的code都是TRANSACTION_send
data.enforceInterface(DESCRIPTOR);
android.os.Message _arg0;
if ((0 != data.readInt())) { // data.readInt为1(当msg不为空时)
_arg0 = android.os.Message.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.send(_arg0);
return true;
}
data.readInt() != 0 说明有内容,对应的是 Proxy 中 send() 方法
if ((msg != null)) {
_data.writeInt(1);
msg.writeToParcel(_data, 0);// 将msg所有字段(what,obj)写到_data中去
} else {
_data.writeInt(0);
}
这一段代码。重点来了 android.os.Message.CREATOR.createFromParcel(data) 这个明显就是反序列化的代码,Message 也实现了Parcelable接口, 看看 Message 中相关部分
public static final Parcelable.Creator
= new Parcelable.Creator
public Message createFromParcel(Parcel source) {
Message msg = Message.obtain();
msg.readFromParcel(source);
return msg;
}
public Message[] newArray(int size) {
return new Message[size];
}
};
public void writeToParcel(Parcel dest, int flags) {
if (callback != null) {
throw new RuntimeException(
"Can't marshal callbacks across processes.");
}
dest.writeInt(what);
dest.writeInt(arg1);
dest.writeInt(arg2);
if (obj != null) {
try {
Parcelable p = (Parcelable)obj;
dest.writeInt(1);
dest.writeParcelable(p, flags);
} catch (ClassCastException e) {
throw new RuntimeException(
"Can't marshal non-Parcelable objects across processes.");
}
} else {
dest.writeInt(0);
}
dest.writeLong(when);
dest.writeBundle(data);
Messenger.writeMessengerOrNullToParcel(replyTo, dest);
dest.writeInt(sendingUid);
}
private void readFromParcel(Parcel source) {
what = source.readInt();
arg1 = source.readInt();
arg2 = source.readInt();
if (source.readInt() != 0) {
obj = source.readParcelable(getClass().getClassLoader());
}
when = source.readLong();
data = source.readBundle();
replyTo = Messenger.readMessengerOrNullFromParcel(source);
sendingUid = source.readInt();
}
这三段代码我们可以明白 Message 如何序列化和反序列化的。
Message _arg0 = android.os.Message.CREATOR.createFromParcel(data); 获取到 Message 对象后,然后 this.send(_arg0); 发送信息,我们知道,send(android.os.Message msg) 是个抽象方法,具体的要找到它的实现类。Service端中 MessengerService 发送信息的方法,Messenger messenger = msg.replyTo; messenger.send(Message.obtain(null, 1));这里的 Messenger 是 msg.replyTo,那么 msg.replyTo 是怎么来的呢?原来是 Activity 中传递进来的, msg.replyTo = mMessenger; 这个mMessenger 是
private Messenger mMessenger = new Messenger(new Handler(){
@Override
public void handleMessage(Message msg){
// 接收远程服务消息
switch (msg.what){
case 1:
Log.e("messenger", "activity ! ");
break;
}
}
});
这里使用的构造方法是 new Messenger(new Handler()),我们知道 public Messenger(Handler target) {mTarget = target.getIMessenger();},看看Handler中的代码
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);
}
}
原来,最终调用的是 Handler.this.sendMessage(msg); 跨线程耗时操作,通过这里最后一步,会进入到UI线程中。为什么没有造成Activity的ANR异常,却还是不清楚,后来查资料,才知道 IMessenger.aidl 接口前面有 oneway 关键字修饰 oneway interface IMessenger{void send(in Message msg)}。没有 oneway 时,mRemote.transact()的最后一个参数是 0;声明 oneway 修饰时,mRemote.transact() 的最后一个参数是 android.os.IBinder.FLAG_ONEWAY, FLAG_ONEWAY 的作用是让客户端可以非阻塞的调用远程方法。还有一点,Messenger 不适合高并发的场景。