一、IPC
进程间通信。多个进程间的数据交互
进程一般是指一个可执行的单元,在PC或移动设备上指一个程序或应用。
线程是CPU最小的调度单元,是一种有限的系统资源
一个进程中可以包含多个线程
如果将一个耗时操作放在主线程,就会造成ANR
Android中进行进程间通信最特色的就是使用Binder,同样也可以使用Socket进行进程间通信
Android可以通过给四大组件指定android:process属性就可以开启多进程模式了
使用多进程会造成:
1、静态成员和单例模式失效
这是因为每个进程会有自己独立的虚拟机,在内存中会分配不同的地址空间,因此在访问同一个类的对象会产生不同的副本,这样该类的对象值发生变化时,对其他进程中的该类对象的值不受影响。
2、线程同步机制失效
原因和1类似
3、SharedPreferences的可靠性下降
SharedPreferences不支持并发写操作,会导致一定几率的数据丢失
4、Application会多次创建
当一个组件跑在一个新的进程中时,系统就会给新的进程分配独立的虚拟机,就是启动一个应用的过程
二、序列化和反序列化
序列化是指把Java对象转换为字节序列的过程
反序列化是指把字节序列恢复为Java对象的过程
用途:
1、实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里)
2、通过序列化对象在网络中传递对象。
3、通过序列化对象在进程间传递对象
serializable、parcelable
1、serializable接口
是Java提供的一个序列化接口。实现起来比较简单,只需要在类的声明的时候实现该接口,同时指明一个serialVersionUID标识即可。
serialVersionUID是用来辅助序列化和反序列化的,Java对象在序列化的过程中会将当前类的
serialVersionUID写到文件中,只有序列化后的数据的serialVersionUID与当前类的serialVersionUID一致才能进行反序列化。
2、parcelable接口
Android提供的新的序列化接口。
Android的Parcelable的设计初衷是因为Serializable效率过慢,为了在程序内不同组件间以及不同Android程序间(AIDL)高效的传输数据而设计,这些数据仅在内存中存在,Parcelable是通过IBinder通信的消息的载体。
实现Parcelable接口主要可以分为一下几步:
<1> implements Parcelable。
<2> 重写writeToParcel方法,将你的对象序列化为一个Parcel对象,即:将类的数据写入外部提供的Parcel中,打包需要传递的数据到Parcel容器保存,以便从Parcel容器获取数据。
<3> 重写describeContents方法,内容接口描述,默认返回0即可。
<4> 实例化静态内部对象CREATOR实现接口Parcelable.Creator 。
3、Parcelable和Serializable的区别:
<1> 在使用内存的时候Parcelable比Serializable的性能高。
<2> Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC(内存回收)。
<3> Parcelable不能使用在将对象存储在磁盘上这种情况,因为在外界的变化下Parcelable不能很好的保证数据的持续性。
<4> 在读写数据的时候,Parcelable是在内存中直接进行读写,而Serializable是通过使用IO流的形式将数据读写入在硬盘上
<5> Parcelable是以Ibinder作为信息载体的.在内存上的开销比较小,因此在内存之间进行数据传递的时候,Android推荐使用Parcelable
三、Binder
Binder是Android的一个类,实现了IBinder接口。是Android中的一种跨进程通信的方式。
在Android开发中,大量使用到了系统Service,比如媒体播放、各种传感器以及WindowManagerService等等。
调用系统服务的过程:
在Android开机启动过程中,Android会初始化系统的各种Service,并将这些Service向ServiceManager注册(即让ServiceManager管理),
客户端想要得到具体的Service直接向ServiceManager查询,得到具体的Service引用,然后通过这个引用向具体的服务端发送请求,服务端执行完成后就返回结果给客户端。
在Android开发中主要用于Service中,包括AIDL和Messenger。其中普通service中的Binder是不涉及进程间通信的。
1、使用AIDL实现进程间通信
<1> 创建MyBook.java、MyBook.aidl、IMyBookManager.aidl三个文件
MyBook实现parcelable接口
MyBook.aidl中声明了MyBook对象:parcelable MyBook;
IMyBookManager.aidl中是一个接口,包含addMyBook、getBookList两个方法
文件创建完成后build项目就会在app/build/generated/source/aidl文件夹下生成一个IMyBookManager.java文件。IMyBookManager.java类继承了IInterface接口,它自己也还是一个接口。它的内部首先声明了在IMyBookManager.aidl中 定义了的两个方法以及声明了两个整型的id用来标识这两个方法,这两个id用于标识在transact过程中客户端所请求的到底是哪个方法。接着声明了一个内部类Stub,这个Stub就是一个Binder类,当客户端和服务端处于同一个进程时,方法调用不会走跨进程的transact过程,而当两者不在同一进程,方法调用就会走transact过程,这个逻辑是由Stub的内部代理类Proxy完成的。这个接口的核心实现就是内部的内部类Stub和Stub内部的代理类Proxy。
<2> 创建远程服务端service类MyBookManagerService
在该类中使用new IMyBookManager.Stub()创建一个Binder对象,并在onBind()方法将该Binder对象返回。然后再AndroidManifest中注册该服务,并为服务指定进程
<3> 客户端进程Activity实现
通过bindService的形式将service绑定到Activity中。然后new ServiceConnection对象在该对象的onServiceConnected(Component className, IBinder service)方法中使用 IMyBookManager.Stub.asInterface(service)来获取IMyBookManager对象,然后通过该对象就可以调用到service进程中的方法addMyBook、getBookList。asInterface(binder)方法用于将服务端的Binder对象转换成客户端所需要的AIDL接口类型的对象,如果客户端和服务端是同一进程,那么就返回的是服务端的Stub对象本身,否则返回的就是系统封装的Stub.proxy对象。代码如下:
public static com.test.demo.test.apiDemo.service.aidl.demo_1.IMyBookManager asInterface(android.os.IBinder obj){
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.test.demo.test.apiDemo.service.aidl.demo_1.IMyBookManager))) {
return ((com.test.demo.test.apiDemo.service.aidl.demo_1.IMyBookManager)iin);
}
return new com.test.demo.test.apiDemo.service.aidl.demo_1.IMyBookManager.Stub.Proxy(obj);
}
在多进程中使用IMyBookManager调用getBookList其实就是调用的是proxy对象对象的Proxy.getBookList方法,由此看来Proxy.getBookList方法是运行在客户端,接着会调用transact方法来发起远程请求,同时当前线程会挂起;然后服务端Binder线程中的onTransact方法就会被调用,直到返回结果,当前线程才会继续执行,由此可以看出 onTransact方法是运行在服务端的Binder线程池中的,它是通过参数code来确定客户端请求的目标方法的。
注意:从上面的分析可以得出当客户端发起请求时,当前线程就会被挂起直到服务端返回数据为止,所以如果一个远程方法很耗时,那么就不能再UI线程中发起远程请求。
2、使用Messenger实现进程间通信
Messenger也成为信使,可以在不同进程中传递Message对象。它的底层实现依然是AIDL,对AIDL进行了封装。
<1> 服务端进程
服务端创建一个Service来处理客户端请求,同时创建一个Handler来接受客户端的消息,并通过该handler来new Messenger(handler)对象,然后在onBind()方法中使用Messenger.getBinder()方法返回Binder对象。然后再AndroidManifest中注册该服务,并为服务指定进程
<2> 客户端进程
通过bindService的形式将service绑定到Activity中。然后new ServiceConnection对象在该对象的onServiceConnected(Component className, IBinder service)方法中使用IBinder对象创建一个new Messenger(service)对象,然后就可以通过该对象的send()方法发送对象了,发送消息的类型是Message对象。
使用上面的步骤就完成了客户端向服务端进程传递消息,如果需要服务端能够回应客户端,那么同样在客户端需要创建一个Handler对象,并通过该handler来创建一个Messenger对象,并把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端在handler中通过这个replyTo参数就可以拿到客户端传递过来的Messenger对象,就可以使用该Messenger对象发送消息给客户端了。
3、使用ContentProvider实现进程间通信
ContentProvider是Android中提供的专门用于不同应用间进行数据共享的方式,和Messenger一样,它的底层同样是Binder