1.前言
2.进程相关的adb命令
adb shell ps 查看所有的进程 adb shell ps pid 查看指定pid进程
adb shell ps | grep 包名 指定包名查看进程信息
adb shell cat /proc/pid/oom_adj 进程回收建议值
3.几种进程间通信的方式
Android的IPC(Inter-Process Communication/进程间通信),可以使用Binder机制与Socket通信来实现,Bundle的Intent附带数据传递,ContentProvider自带实现了夸进程数据共享。Android的ShareUID模式可以使两个具有相同shareUID并且签名相同的应用共享数据(data目录,组件信息,内存数据),他们看起来就像一个应用的两个部分。
4.多进程带来的问题
系统在创建新的进程会分配独立的虚拟机,相当于启动一个应用,创建新的Application。所以,不同进程会拥有独立的虚拟机,Application以及内存空间。一个应用的多进程模式可以理解为多个应用采用了ShareUID模式。
具体造成的影响:
- 静态成员和单例模式完全失效。
- 线程同步机制完全失效。
- SharedPreferences不可靠.用ContentProvider包装过的SharePreferences,多进程下可靠.
- Application创建代码多次执行,每增一个进程,相当于启动一个应用,分配独立的虚拟机与内存。
5.开启多进程
Android中只能通过给四大组件设置android:process来开启多线程,无法给一个实体类或者线程指定进程,代码运行在哪个线程,取决于调用代码的组件.进程名以":"开头的为私有进程,其他为公有进程,公有进程可以使用ShareUID方式运行其他相同签名应用的组件(很少用).
6.序列化
Intent与Binder传递数据需要先进行序列化.
serializable是Java的序列化实现,用于对象与存储设备的读取保持,使用简单,大量I/O操作开销大.serializable需要指定serialVersionUID,默认使用实体类的hash值.如果不指定serialVersion,当类进行改动,hash变化,就会造成反序列化失败,程序Crash.
静态成员变量属于类不属于变量,不参与序列化.transient关键字标记的成员变量不参与序列化.
Parcelable是android特有的,使用起来麻烦,主要是在内存序列化,效率高。
7.AIDL
- 客户端调服务端代码是定义一个AIDL接口,由服务端实现,然后在bind的回调中返回给客户端.如果在这个接口中定义方法能够将另一个AIDL接口A传给服务端,客户端实现A接口,那么服务端就能通过此接口方便的调用客户端接口.在Demo中IOnNewBookArrivedLIistener与NewBookReceiverActivity展示了这种用法.
- 服务端管理客服端接口要使用RemoteCallbackList,不然无法解绑客服端的推送.原因是:当客服端的书籍提醒接口实现实例通过AIDL接口方法传递到服务端会变成一个新的对象,用一般的List管理客服端接口在添加的时候添加的是新的对象(同一方法参数的新旧对象在AIDL中有一一对应的关系,这就是为什么服务端调用新对象的方法,客服端旧对象能够响应,猜测,TODO),解绑方法的参数,传递到服务端也是一个新的对象.这就造成接口管理List找不到注册时添加的接口,造成解绑失败.而RemoteCallbackLis是系统专门提供的用于跨进程listener的接口.工作原理是用一个Map结构存储接口.同一客户端跨进程传输参数服务端会产生新对象,但是它的底层Binder对象是不会变的,所以可以用它作为key来标识客户端,value则是客服端接口.且客服端挂了会自动移除相应键值对,自动支持线程同步.beginBroadCast和finishBroadCast必须配对使用.
- 如果服务端不使用RemoteCallBackList管理回调接口,发现先由MainActivity绑定PushService,再启动NewBookReceiverActivity的AIDL接口会被不断的回调,即使已经调用了Destroy().弄不明白为什么会这样,TODO.
push进程挂掉监听.
权限验证,在onTransact中调用,注意不要在onBind中判断权限.
8. Messenger
Messenger通信这种方式是利用Handle消息队列互传消息,意味着这种方式是串行的.同时无法直接调用其他进程的方法,只能根据收到的消息来调用方法.返回值也只能用消息传递
9.in/out/inout参数标记探索
protected Book(Parcel in) {
readFromParcel(in);
}
public void readFromParcel(Parcel in) {
id = in.readInt();
name = in.readString();
price = in.readDouble();
}
总结:
- in表示服务端将接收传入的参数(Book book).服务端对接收到参数(book)做修改,客户端不会同步修改book;
- out表示服务端将不接收传入的参数(Book book),从源码看是新new了一个对象.服务端对接收到参数(book)做修改,客户端会同步修改book;
- inout表示服务端接收传入的参数(Book book.服务端对接收到参数(book)做修改,客户端会同步修改book.
10.TCP实现进程通信
11.Binder管理(连接池)
我们希望在一个远程进程中处理很多不同的业务(实际场景没有遇到过),假设需要在远程进程中处理计算与安全中心业务。常规的做法是开2个service,这2个serivce跑在同一个进程中。现在想只用一个service就能处理很多不同的功能。
声明IBinderPool.aidl,有方法Binder queryBinder(int code)。在连接完Service后,得到IBinderPool型的Binder对象,传入定义好的code调用此对象的queryBinder得到对应的业务aidl的Binder对象。
用单例类将连接service,请求得到binder管理起来,完成一个实例一个连接能返回多个binder的目的。
IPC方式对比
- Intent,Bundle: 简单易用,单向,多用于四大组件传递初始数据,最多数据量1M
- 文件交互: 不支持多并发,操作麻烦,局限性大
- Socke:t 功能强大,双向通信,实现与维护困难,多用于网络通信
- ContentProvider 适用于数据提供,数据源共享,不适合数据交互与RPC(远程过程调用)
- Messenger: 实现简单一对一还好,并发处理困难,RPC困难
- AIDL: 功能强大,拓展性强,支持多并发,需要处理好线程同步,支持RPC