IPC Inner-Process Communication 进程间通信
- 线程 线程是CPU调度的最小单元,同时线程是一种有限的系统资源
- 进程 进程指一个执行单元,PC 和 移动设备中指一个程序或者一个应用
process 开启多进程
- native 层也可以 fork 新的进程
- 有 : 以冒号简写和写完整进程名两种方式
- 以 :冒号方式,表明该进程是属于该应用的私有进程,其他应用组件不可以和他跑在同一个进程
- 不以 :冒号开头的进程属于全局进程,其他应用通过 ShareUID 方式可以和他跑在同一进程
adb 命令行查看
adb shell ps
adb shell ps | package name
多进程存在的问题
- 静态变量、单例模式完全失效
- 线程同步机制完全失效
- SharedPreferences 可靠性下降
- Application 会多次创建
IPC 方式
- Intent 传输
- 文件共享
- Messenger
- Soket
- AIDL
- ContentProvider
一、Inten
Intent 中的 Bundle 支持在不同进程间传递数据,启动另一进程 Service、Activity、BroadcastReceiver 时可以通过 Intent 传递数据
二、使用文件共享
- 共享文件也是一种方式,A 进程在文件中序列化进去一个对象,B 进程在文件中读取并恢复。
- 缺点:并发读写不可控
- 用于:是合租对数据同步要求不高的进程间进行通信,并妥善处理并发的读写问题
- SharedPreferences 同共享文件类似,不过对 SharedPreferences 的读写系统有一定的缓存机制,操作不当容易丢失数据,不建议在多进程通信中使用
三、Messenger
- 服务端:创建一个 Handler 对象,由 Handler 对象构造一个 Messager 对象 Messager msgr = new Messager(handler) ,在 onBind() 方法中返回由 Messager.getBinder() 得到的 Bindler 对象
- 客户端:onServiceConnected() 方法中,有 Binder 对象创建一个 Messenger 对象,通过 Messenger 对象的 send(Message msg) 方法将需要跨进程的数据发出
- 服务端:在 Handler 中根据 Msg 的 what 属性做出相应的处理
解析 Messager msgr = new Messager(handler); 方法
该构造方法内部,为 Messenger 的 IMessenger 对象初始化,其实是赋值了 Handler 的内部类 IMessenger.Stub 类的对象,IMessenger.Stub 类似于 Binder 解析过程中,自动生成的 AIDL 类中的 Stub 类,重写了 sendMessage 方法,Messager 的 send 方法是发送消息的,这里使用调用当前创建 Messenger 的 Handler 的 sendMessage 方法。Handler 发送的消息,最后的处理还是当前 Handler。
Messenger 的 getBinder 方法返回了内部的 IMessenger 对象的 asBinder() 方法的返回值。类似于 Binder ,说明,IMessenger.Stub 是继承了 Binder 的。所以最后 Messenger 的 getBinder 方法的到的就是 AIDL 过程中,那个 Stub 类的实现类对象。对了,没毛病
将 IMessenger.Stub 这个 Binder 类传递到客户端,客户端会调用 Messenger mesger = new Messenger(IBinder binder) 方法得到 Messenger 对象,可以清晰的看的,类似 AIDL 客户端的处理过程,客户端根据 IBinder 对象得到了 Messenger 类型的对象。
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}客户端通过 IMessenger.Stub 的 send 方法跨进程发送消息,其实是调用了在服务端中的 Handler 发送消息的方法。只不过在发送消息的时候 IMessenger.Stub 的 send 方法是会将需要传递的参数先序列化,传递到服务端后反序列化,再由反序列化得到的数据让服务端的 Messenger 对象来处理,即调用 Handler 的发送方法,最后处理任务在 服务端,直到结束。
Messager:
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}Handler:
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}MessageImpl:
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}如果客户端需要在发出消息之后还能收到服务端的消息,就需要客户端在绑定成功后也创建自己的 Handler 对象创建 Messenger 对象,并通过 send 方法中的 Messge 对象的 replyTo 参数将 Messenger 穿递到服务端,服务端通过 Message 的 replyTo 参数也会得到 Messenger 对象。也就可以通过客户端传来的 Messenger 对象来向客户端发送消息了。
Message 的 replay 参数类型是一个 Messenger ,可以使用 Messege 来携带 Messenger 对象。
Messenger 的 getMessenger(Handler h) 方法封装了 AIDL 中 IBinder b = new IMessenger.Stub 过程
Messenger 的 getMessenger(IBinder binder) 方法封装了 Messenger msger = IMessenger.Stub.asInterface(IBinder b) 过程
Messenger 一次处理一个请求,所以也不用考虑线程同步的问题,因为使用的是 Handler 处理数据, 消息队列中的消息是串行执行的。
Binder 连接池
- 使用 BinderPool 绑定 Service ,
- 创建 不同的 AIDL ,生成器实现类
- 创建 IBinderPool 的 AIDL 接口,定义根据 CODE 获取 IBinder 的方法
- 创建 Service ,onBind 方法中返回 IBinderPool 类型的 IBinder
- 客户端中得到 IBinderPool 对应的 IBinder 对象
- 客户端中由 IBinder 对象的 query 方法传入 CODE 调用服务端的 服务,返回需要的 IBinder
客户端根据 IBinder 再调用服务端相应服务
注意:bindService 的过程必须结束之后才可以使用得到的 IBinder 对象进行操作,否则会空指针客户端每次请求的时候需要两步,第一步要先绑定 Service 获取 IBinderPool 的 IBinder
- 第二部,由 IBinder 转化为 IBinderPool 类型
第三部,进行操作
Binder 连接池的作用为,将以上两部进行封装,在 BinderPool 初始化的时候就完成与Service 的绑定也就是得到 IBinder 对象
- 客户端直接使用该 IBinder 对象的 query 方法就可以得到想要的 Binder