IPC:Inter-Process Communication,进程间通信或跨进程通信
- part2-1 线程与进程
一个应用程序对应一个进程,一个进程最少由一个线程(主线程)组成,线程是CUP调度的最小单位
- part2-2 Android中的多进程
Android四大组件可以通过android:process=”“属性来开启多进程
- Get:
- 可通过android:process=”:remote”或android:process=”自定义进程名”配置多进程,进程名一般指定当前包名+后缀(自定义)。其中:remote为当前包名+:remote的缩写,属于当前应用的私有进程,其他应用的组件不可以跑进这个进程;自定义进程名开启的为全局进程,其他应用通过ShareUID方法可以和它跑在同一个进程中。
- 使用多进程会带来几个问题:
- 静态成员和单例模式完全失效
- 线程同步机制完全失效
- SharePreference可靠性下降
- Application会多次创建
- Get:
- part2-3 IPC基础
如果一个对象想通过Intent和Binder传递,该对象需要序列化,可通过Serializable接口或Parcelable接口实现序列化。
- Get:
- Serializable
使用Serializable接口序列化时,通过指定一个serialVersionUID可以更好的实现反序列化;如果没有指定serialVersionUID,当对象的成员发生改变时,反序列化会失败。 - Parcelable (借用书中例子:一个典型的实现了Parcelable 接口的对象类)
- Serializable
- Get:
public class Book implements Parcelable {
public int bookId;
public String bookName;
public Book() {
}public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}//“内容描述”,如果含有文件描述符返回1,否则返回0,几乎所有情况下都是返回0
public int describeContents() {
return 0;
}//实现序列化操作,flags标识只有0和1,1表示标识当前对象需要作为返回值返回,不能立即释放资源,几乎所有情况都为0
public void writeToParcel(Parcel out, int flags) {
out.writeInt(bookId);
out.writeString(bookName);
}//实现反序列化操作
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
//从序列化后的对象中创建原始对象
public Book createFromParcel(Parcel in) {
return new Book(in);
}
public Book[] newArray(int size) {//创建指定长度的原始对象数组
return new Book[size];
}
};
private Book(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}}
- 对比
Serializable是Java提供的接口,使用简单,但开销大,需进行大量I/O操作;Parcelable是Android中的序列化方式,使用麻烦,但效率高,是Android推荐使用的方式。但由于其过程复杂,我们更多使用的是Serializable。
intent().putExtra(String name, Serializable value)
intent().putExtra(String name, Parcelable value)
getIntent().getSerializableExtra(name);
getIntent().getParcelableExtra(name);
- Binder机制((难理解,详见原书,引用书中对Binder的直观描述)
- Binder是Android中的一个类,它实现了IBinder接口。从IPC角度看,Binder是Android中一种跨进程通信的方式;Binder还可以理解为虚拟的物理设备,它的设备驱动是/dev/binder;从Framework层角度看,Binder是ServiceManager连接各种Manager和相应的ManagerService的桥梁;从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。
- Android中的IPC方式
- Bundle
实际开发中我们最常使用的传递数据方式,其通过了Map的key+vaule形式保存数据。Activity、Service、BrocastReviever都支持使用Intent传递Bundle数据,Bundle支持的类型有:基本类型的数据和基本类型的数组数据、String/CharSequence类型的数据和数组数据、实现了Serializable接口或Parcelable接口的对象以及一些Android支持的特殊对象。
Get:
Bundle内部其实是实现了Parcelable接口。
- 使用文件共享
适合在对数据同步要求不高的进程之间进行通信,并且要妥善处理并发读写的问题。
Get:
我们经常使用的Sharepreference属于特殊的文件共享方式,系统对它的读写有一定的缓存策略,会在内存中有一份SharedPreferences文件的缓存,因此在多进程模式下,系统对它的读写就变得不可靠,当面对高并发读写访问的时候,有很大几率会丢失数据,因此,不建议在进程间通信中使用SharedPreferences,更多是在同一个进程或多线程中使用。
- 使用Messenger(难理解,详见原书)
Messenger是一种轻量级的IPC方案,它的底层实现就是AIDL,以串行的方式处理客户端发来的消息。
- 使用AIDL(难理解,详见原书)
- 客户端通过绑定远程服务,在onServiceConnected方法中将服务器端返回的Binder对象转换成AIDL接口,然后通过这个接口调用服务器端远程方法。
Get:
AIDL支持的数据类型:基本数据类型、String、CharSequence、ArrayList、HashMap、Parcelable序列化的对象以及AIDL本身
- Bundle
- 使用ContentProvider(详见原书)
【《Android开发艺术探索》读书笔记--part2 IPC进程间通信机制】ContentProvider底层实现了Binder机制,系统已经做了封装,使用时变得简单,需自定义一个类继承 ContentProvider,然后覆写 query、insert、update、delete 等方法,通过URI的匹配来实现增删改查,并在 AndroidManifest 文件中进行注册。
- 与ContentProvider相关的几个类
ContentProvider :内容提供者,用于对外提供数据
ContentResolver :内容解析者,用于获取内容提供者提供的数据
ContentResolver.notifyChange(uri)发出消息
ContentObserver :内容监听器,可以监听数据的改变状态
ContentResolver.registerContentObserver()监听消息
- 与ContentProvider相关的几个类
- 使用Socket(详见原书:基于Socket的简易网络聊天室)
- part2-4 Binder连接池(详见原书)
当项目规模很大的时候,创建很多个Service是不对的做法,因为service是系统资源,太多的service会使得应用看起来很重,所以最好是将所有的AIDL放在同一个Service中去管理。整个工作机制是:每个业务模块创建自己的AIDL接口并实现此接口,这个时候不同业务模块之间是不能有耦合的,所有实现细节我们要单独开来,然后向服务端提供自己的唯一标识和其对应的Binder对象;对于服务端来说,只需要一个Service,服务端提供一个queryBinder接口,这个接口能够根据业务模块的特征来返回相应的Binder对象给它们,不同的业务模块拿到所需的Binder对象后就可以进行远程方法调用了。Binder连接池的主要作用就是将每个业务模块的Binder请求统一转发到远程Service去执行,从而避免了重复创建Service的过程。
- part2-4 选用合适的IPC方式
文章图片
第二章内容到此结束,主要讲了进程间通信机制,由于比较多涉及到底层原理,所以以目前来说比较难以看懂
推荐阅读
- 从零开发一个完整的Android项目(九)——图片浏览
- Android开发|ViewPager自适应高度问题
- Android|Android 指定销毁一个Activity
- 【Android】简单图片浏览器
- 理解ButterKnife(自动生成绑定资源的代码)
- MAC下搭建Android Studio
- NestedScrollingParent 和NestedScrollingChild 实现嵌套滑动
- android用shape画一条横线
- 华为推送 的坑
- Duplicate class com.alipay.a.a.a found in modules classes.jar (:alipaySdk-15.6.2-20190416165036:) an