Android IPC 简介
- 进程间的通讯(Inter-Prosses communication),简称IPC
- 进程间通讯方式有很多,如Bundle、Socket、文件、管道、Messager、Provider、AIDL等
- 设置多进程方式,
manifest
配置android:process=":remote"
或者android:process="com.song.androidstudy.remote"
:remote
方式进程名为包名 +:remote
,否则为com.song.androidstudy.remote
:remote
开头的进程是当前应用的私有进程,其他进程的组件不可以跑在一起,但是非:
开头的进程可以通过相同的sharedUID
跑在同一个进程当中,为全局进程。- 静态成员和单例对于完全失效,线程同步完全失效,
Application
会创建多次,SharedPreferences
可靠性下降(虽然可以进程间通讯,但系统会缓存)
对象序列化
Serializable
- 实现
Serializable
接口,且声明serialVersionUID
即可实现序列化和反序列化,注意serialVersionUID
并不是必须的 - 序列化的时候系统会把当前类的
serialVersionUID
写入系列化的文件中,当反序列化的时候系统会去检测文件中的serialVersionUID
,看它时候和类中的serialVersionUID
一致,如果一致就说明序列化类的版本和当前类的版本是相同的,这个时候可以成功反序列化。否则就说明当前类和序列化类发生了某些变换,可能报InvalidClassException
。 - 可以手动指定
serialVersionUID
,也可以通过工具生成当前类的hash
值作为serialVersionUID
。但并不是只要serialVersionUID
相同反序列化就会成功,如果类发生了非常规性改变,如改了类名、改了属性名称反序列化就会失败。 - 静态成员变量属于类不属于对象,不会参与序列化和过程;
transient
关键字标记成员变量不参与序列化过程 - 重写
writeObject
和readObject
方法可以自定义序列化过程
Parcelable
只要实现 Parcelable 接口,对象就可以实现序列化并可以通过 Intent 和 Binder 传递数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class User implements Parcelable {
private int userId;
private String userName;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.userId);
dest.writeString(this.userName);
}
public void readFromParcel(Parcel source) {
this.userId = source.readInt();
this.userName = source.readString();
}
protected User(Parcel in) {
this.userId = in.readInt();
this.userName = in.readString();
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel source) {
return new User(source);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
}
Parcelable 方法说明
方法 | 功能 | 标记位 |
---|---|---|
createFromParcel(Parcel source) | 从序列化后的对象中创建原始对象 | |
newArray(int size) | 创建指定长度的原始对象数组 | |
User(Parcel in) | 从序列化后的对象中创建原始对象 | |
writeToParcel(Parcel dest, int flags) | 将当前对象写入序列化结构中,其中 flags 标识有两种:0和1(参见右侧标记位),为 1时标识当前对象需要作为返回值返回,不能立即释放资源,几乎所有情况都返回 0。 | PARCELABLE_WRITE_RETURN_VALUE |
describeContents() | 返回当前对象的内容描述。如果含有文件描述符,返回1(参见右侧标记位),否则返回 0,几乎所有情况都返回 0。 | CONTENTS_FILE_DESCRIPTOR |
Intent、Bundle、Bitmap、List、Map 也可以序列化,前提是其里面每个元素都是可序列化的。
Parcelable 和 Serializable 区别
- Serializable 是 Java 中序列化接口,其使用起来简单但是开销很大,序列化和反序列化过程需要大量的 I/O 操作
- Parcelable 使用稍微麻烦些,但是其效率高适合在 Android 中使用
- 在内存中首选使用 Parcelable,但是在文件和网络中推荐使用 Serializable
https://www.jianshu.com/p/32a2ec8f35ae ,Parcelable序列化速度比Serializable快10倍
选用合适的IPC方式
- bundle 利用 intent 传递数据,只支持序列化的数据,且数据量不宜过大
- 文件通讯,并发支持弱,因为 android 文件读写没有锁
- SharedPreferences,可靠性弱,且不支持并发
- Messager 底层实现为 AIDL,轻量级的 IPC 机制,一次只执行一次请求,不支持并发,通过 Message 传输数据
名称 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
Bundle | 简单易用 | 只能传递Bundle支持的数据类型 | 四大组件间的进程间通信 |
文件共享 | 简单易用 | 不适合高并发场景, 并且无法做到进程间的即时通信 | 无并发访问情形, 交换简单的数据实时性不高的场景 |
AIDL | 功能强大,支持一对多并发通信,支持实时通信 | 适用稍复杂,需要处理好线程同步 | 一对多通信且有RPC需求 |
Messenger | 功能一般,支持一对多穿行通信,支持实时通信 | 不能很好处理高并发情形, 不支持RPC,数据通过Message进行传输,因此只能传输Bundle支持的数据类型 | 低并发的一对多即时通信,无RPC需求,或者无须要返回结果的RPC需求 |
ContentProvider | 在数据源访问方面功能强大,支持一对多并发数据共享,可通过Call方法扩展其他操作 | 可以理解为受约束的AIDL,主要提供数据源的CRUD操作 | 一对多的进程间的数据共享 |
Socket | 功能强大,可以通过网络传输字节流,支持一对多并发实时通信 | 实现细节稍微有点繁琐,不支持直接的RPC | 网络数据交换 |