Android 常见的几种进程间通信
在Android中,存在着很多种进程间通信。一般而言,Activity之间、广播是通过Intent传输数据的。Service与Activity之间是通过AIDL。其他例如文件通信,用得比较少,实时性差。
Intent 通信几乎和进程内通信的方式一样,没有什么特别之处。所以今天我们来梳理一下AIDL以及AIDL的封装messenger。
用法
预备知识:
- 如何启动Service?
启动Service有两种方式,一种是startService,一种是bindService。startService只能通过广播进行进程间通信。而bindService会返回一个远程接口,可调用者调用。
Messenger通信
简单来说,就是把IBinder接口,用Messenger进行包装。在服务端,为了解决线程安全性的问题,用Handle进行串行处理。
Messenger在服务端接收时,是用Handle接收的,会给新手一个假象是:Handle可以跨进程通信。
对于新手,要警惕别人来问一个问题是:Handle机制的三剑客(Looper、MessageQueue、Handle)都没有跨进程的能力,为什么服务端可以用Handle来接收呢?
不要急,不要急,我们来分析一下Messenger的源码。
来看一下客户端。
在得到IBinder接口后,会进行IBinder封装。
Messenger messenger = new Messenger(service);
然后,要进行数据的发送,可以通过send方法发送一个Message给客户端:
messenger.send(Message.obtain(null,MSG_SAY_HELLO,0,0));
我们看一下Messenger.send里面做了什么。
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
send方法里调用mTarget.send,mTarget是一个IMessenger对象。在Messenger的构造方法里进行初始化,看一下构造方法。
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
可以看到 mTarget 从 IMessenger.Stub.asInterface 中来,如果是有用过AIDL的同学看到这里应该很明白了,在使用的AIDL的时候,客户端拿到IBinder接口后,需要调用AIDL的自动生成的代码转化一下接口。
所以,Messenger的客户端,其实基于AIDL,并且Messenger有一个send方法可以进行远程通信。
来看一下服务端
服务端在onBind方法,把服务端的远程接口返回去了。
@Override
public IBinder onBind(Intent intent) {
mMessenger = new Messenger(new IncomingHandler(this));
return mMessenger.getBinder();
}
只不过,是先创建Messenger对象,然后通过getBinder得到远程接口。
先看下Messenger(Handle handle)这个构造方法。
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
可以看到,在构造方法里,初始化了mTarget对象。mTarget对象是一个IMessenger接口,通过分析Handle.getIMessenger可以知道具体实现是MessengerImpl。看一下MessengerImpl这个类。
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
MessengerImpl 类很简单,继承IMessenger.Stub,有一个send方法的定义。学习过AIDL的同学看到这里已经明白了,Messenger的服务端实现也是基于AIDL。因为服务端在使用AIDL时,是需要继承Stub的。
所以,当客户端调用send方法时,数据会经过Binder驱动,AIDL解析之后调用服务端的send方法。在服务端的send方法中,会进行一个数据的串行处理,使之线程安全。
分析完客户端给服务器发送消息的流程,那么有同学一定有疑问是:服务端如何回消息呢?这里就不演示啦,具体做法如下:
如果需要服务端回复,可把客户端也创建一个Messender并且也放入message中,服务端在获取到客户端的Messender然后发送回来即可
好了,Messenger的分析就到此,下一篇将分析Messenger的底层实现AIDL的使用方式以及java层的代码分析。