每天都要写点笔记,哪怕是自己给自己看也好。
一、Android IPC简介
1.Android进程间通信的几种方式:
- Bundle(Intent)
- 文件
- AIDL
- Messenger
- ContentProvider
- Socket
2.多进程的几种情况
- 应用因为某些原因自身需要采用多进程模式来实现(有些模块需要运行在单独的进程中或者为了加大一个应用可使用的内存)
- 当前应用需要向其他应用获取数据
二、Android中的多进程模式
1.如何开启多进程
给四大组件在AndroidManifest中指定android:process属性
android:process=":remote"
默认的进程名为包名com.ryg.chapter_2,这种形式的进程名为com.ryg.chapter_2:remote
或者
android:process="com.ryg.chapter_2.remote"
2.两种开启多进程模式的区别
- 进程名以“:”开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中
进程名不以“:”开头的进程属于全局进程,其他应用通过ShareUID方式可以和它跑在同一个进程中。
Android系统会为每一个应用分配唯一的UID,具有相同UID的应用才能共享数据。
①ShareUID相同
②签名相同
当①和②都具备之后,两个应用还不一定跑在同一个进程中,此时两个应用能共享data目录、组件信息,如果具备③,也就是
③跑在同一个进程中
那么两个应用还可以共享内存数据,或者说他们看起来就像一个应用的两个部分Android为每个应用分配了一个独立的虚拟机,或者说为每个进程都分配了一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这就导致在不同的虚拟机中访问同一个对象会产生多份副本。
3.多进程带来的主要影响
运行在不同进程中的四大组件,只要他们之间需要通过内存来共享数据,在直接指定android:process属性,不通过中间层来共享数据的情况下,都会共享失败(不同进程的组建会拥有独立的虚拟机、Application以及内存空间)
4.使用多进程会造成的问题
①静态成员和单例模式完全失效
②线程的同步机制完全失效
③SharedPrefrences的可靠性下降
④Application会多次创建(运行在同一个进程中的组件是属于同一个虚拟机和Application的,运行在不同进程的组件是属于两个不同的虚拟机和Application的)
三、IPC基础概念介绍
Serialzable和Parcelable接口可以完成对象的序列化
- 需要通过Intent和Binder传递数据时
- 需要把对象持久化到存储设备上
- 需要把对象通过网络传输给其他客户端
我们可以通过重写writeObject和reabObject这两个方法来重写系统默认的序列化和反序列化过程
注意点:静态成员变量属于类不属于对象,不会参与序列化过程;用transient关键字标记的成员变量不会参与序列化过程
1.Serializable接口
步骤:
①实现Serialzable接口
②声明一个变量serialVersionUID
为什么要指定serialVersionUID呢?
这是因为如果我们不指定serialVersionUID,编译器会为我们生成一个serialVersionUID,如果我们的反序列化的时候,修改了当前类的字段或者方法,serialVersionUID不一致,反序列化就会失败。所以手动指定serialVersionUID的值能够很大程度避免反序列化的失败。
(但是如果类结构发生毁灭性的改变,类的名字改变或者成员变量的类型改变,反序列化还是会失败)
如何指定serialVersionUID?
- 可以指定为1L
- Android Studio有一个插件GenerateSerialVersionUID可以自动生成,安装这个插件之后,按住Alt+Insert就能生成serialVersionUID
public class User implements Serializable{
public static final long serialVersionUID = -5289360048700625611L;
}
2.Parcelable
步骤:
①实现Parcelable接口
②序列化writeToParcel方法
@Override public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(userId);
dest.writeString(userName);
dest.writeInt(isMale ? 1 : 0);
dest.writeParcelable(book,0);
}
③反序列化CREATOR
public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>(){
@Override public User createFromParcel(Parcel source) {
return new User(source);
}
@Override public User[] newArray(int size) {
return new User[size];
}
};
public User(Parcel in){
userId = in.readInt();
userName = in.readString();
isMale = in.readInt() == 1;
//当前线程上下文的类加载器
book = in.readParcelable(Thread.currentThread().getContextClassLoader());
}
④内容描述describeContents方法(几乎所有的情况这个方法都返回0,仅当当前对象存在文件描述符时,此方法返回1)
@Override public int describeContents() {
return 0;
}
注意:当一个类实现Parcelable接口,且里面包含一个对象也必须是可序列化的(实现了Serialzable或者Parcelable接口)
Intent、Bundle、Bitmap都实现了Parcelable接口,List和Map也可以序列化,前提是它们里面的每个元素都是可序列化的
3.两者的区别
- Serialzable使用简单开销大,序列化和分序列化需要大量的I/O操作(对象序列化到存储设备或通过网络传输建议使用Serialzable)
- Serialzable使用起来麻烦但效率高(主要用于内存序列化)
Binder
如何理解Binder?
- 跨进程通信方式
- 虚拟的物理设备
- 是ServiceManager连接各种Manager和相应ManagerService的桥梁
- 是客户端和服务器通信的媒介
参考资料:《Android开发艺术探索》
如果有不对的地方,请各位读者指出