IPC机制
开启多线程
1) 为什么要多线程?
- 特殊的原因自身需要运行在单独的进程中;
- 为了加大一个应用可使用的内存(待验证)
- 从其他应用获取数据
2)如何开启多线程?
唯一办法给四大组件在manifest里指定android:process
属性。
:newProcess 和newProcess的区别在于以:开头的是种简写方式,完整的进程名是包名+:newProcess
,并且它是私有的,不可被共享;没有:开头的则是全局进程,通过ShreUID的方式可以和它跑在一个进程中。
3)多进程带来的问题?
分析:一个应用(或者一个进程)会被分配一个单独的虚拟机,不同的虚拟机在内存分配上是不同的地址空间,这样在不同的虚拟机中访问同一个对象就会有多个副本。所有通过内存的数据共享都会失败。
多线程带来的问题:
- 静态成员和单例模式失效
- Application会被多次创建
- 所有内存间的通信全部失效
- 线程间的同步失效
- SharedPreferences可靠性下降
- 属于文件存储,但是系统对它的读写有缓存的策略,即在内存中有份SharedPreferences的换成你。
Serializable 和 Parcelable
- serialVersionUID:保证反序列化不会因为结构发生变化而无法解析;
- 可重写Serializable的序列化和反序列化的逻辑,只要重写writeObject和readObject方法即可。
区别:
- Serializable是java种的类,使用简单但是开销很大,序列化和反序列化需要大量的I/O操作;
- Parcelable则效率更高,但使用少复杂
- 在内存序列化上,建议使用Parcelable;其他的如存储、网络传输可考虑Serializable;
android中进程通信的方式
1) Bundle
Bundle实现了Parcelable接口,因而可以在不同进程间传输。
2) 文件共享
并发的问题,保证数据可靠
3) Messenger
轻量级的IPC方案,底层实现是AIDL。
特点:
- 服务端一次只处理一个请求,所有的请求都是串行的;
- 不适合高性能并发数据处理
4) AIDL
aidl文件
支持的数据类型:
- 基本数据类型
- List,仅ArrayList
- Map,仅HashMap
- Parcelable,所有实现了Parcelable接口的对象
- AIDL,所有的AIDL接口本身可以再AIDL文件中使用
注意的点:
- Parcelable和AIDL对象在使用时,必须显式的import进来,不管是否存在于一个包中。
- 在aidl文件中使用自定义的Parcelable对象,必须新建一个和该对象同名的AIDL文件,并声明为parcelable。
- 除了基本类型,其他类型都必须标上方向:
in
、out
、inout
- aidl的包结构在服务端和客户端应该保持一致,否则无法解析
AIDL本身的说明
【问题】所有传给server的对象,经过Binder时,binder都会把客户端传过来的对象转换成新的对象。所以,不能说在客户端上equals的对象,在server上也是equals的。
【方案】使用RemoteCallbackList。RemoteCallbackList 内部实现了对象和binder的映射关系。binder在同一个进程中是不变的,这样可以保证即使对象变了,也能找到一一的映射。
server端是不稳定的,随时可能会死掉,所以需要知道连接断开,并重连。
- 通过设置
DeathRecipient
监听; - 另外就是
onServiceDisconnected
两者的区别在于onServiceDisconnected是在主线程,而DeathRecipient实在客户端的Binder线程池中。
权限的校验:保证服务端的访问是有限制的,不是随意性的访问。 比如:onBind里校验、onTransact里校验。
5) ContentProvider
contentprovider的底层数据存储可以是数据库、可以是文件,甚至可以是内存对象。只要实现了query、update、insert、delete方法即可(存在多线程并发访问的问题)。
遗留的问题:
1. 数据库的操作学习。
2. 数据库的onUpgrade 和 onDowngrade怎么实现?
3. 如何做到sql注入的预防?
6) Socket
深入理解Binder
Binder可以理解为虚拟的物理设备,它甚至有自己的驱动设备/dev/binder。
aidl生成的java文件分析:
1)首先它会继承IInterface;
2)它会声明在aidl文件中定义的所有方法;同时针对每个方法声明一个整型的id来分别标记(为了在通信的时候,能够知道是请求的哪个方法);
3)内部类:Stub 和 Proxy,Proxy是Stub的内部类 Stub就是一个Binder,继承了Binder。
- asInterface():用于将服务端的binder对象转换成客户端所需要的AIDL接口类型的对象。
- 这里会根据服务端和客户端是否位于同一进程返回不同的对象。同一进程的就直接返回Stub对象本身;否则是返回系统封装后的Stub.Proxy。
- 核心方法:
Binder#queryLocalInterface()
- asBinder():返回当前进程的Binder
- onTransact():这是Stub的方法,运行在服务端的Binder线程池中,远程请求最终会交给这个方法处理。最终通过reply写入返回值返回给客户端。
- 由
transact()
方法触发;
- 由
客户端发起远程请求时,当前的线程会被挂起,直到等到服务端的数据返回,所以aidl是个阻塞操作,不能在主线程中执行。
通信方式总结
- Bundle简单,只要是四大组件间的进程通信,只能传输Bundle支持的数据类型;
- file/sharedPreference对并发访问支持的不好;
- AIDL功能强大,在一对多并发访问时可用
- Message串行通信,只能支持数据传输,且是Bundle支持的数据类型;
- ContentProvider对数据访问上功能就比较好;
- Socket网络数据交换;