Android中的IPC

2018-09-03  本文已影响0人  草帽小子J

Ipc即为跨进程间通信,既然涉及到进程间通信,必然是多进程;

Andorid中的多进程

Android中多进程分为一个应用中不同组件在不同进程中和需要进行跨进程或者是跨应用进行数据交换和获取两种情况。
将Android应用变为多进程应用只需要在其组件中指定android:process属性,还有种方法就是通过JNI在native层fork一个进程。
这里有一个关于多进程的tips.

  • 指定的进程名以“:”开头:表明当前进程为私有进程,其他应用组件不能和它允许在一个进程,
  • 而进程名不以”:”开头的进程属于全局进程,其他应用通过ShareUID方式可以和它跑在同一个进程中。
  • Android系统为每个应用分配唯一的UID,UID相同才能共享数据。
  • 两个应用通过ShareUID跑在同一个进程中是有要求的,需要这两个应用有相同的ShareUID并且签名相同才可以。如果它们跑在同一个进程中,那么除了能共享data目录、组件信息,还可以共享内存数据,或者说它们看起来就像是一个应用的两个部分。

多进程模式的运行机制

Android为每个应用分配一个独立的虚拟机,即每个进程分配独立的虚拟机,不同的虚拟机在不同的内存分配有不同的地址空间,因此会导致不同的虚拟机上访问同一个类的对象会产生不同的副本,因此在不同进程的四大组件通过内存进行数据共享都会失败。
因此在Android中使用多进程需要注意以下几点:

Android中的序列化

原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同时才能够正常的被反序列化。
serialVersionUID的详细工作机制:序列化的时候系统会把当前类的serialVersionUID写入序列化的文件中(也可能是其他的中介),当反序列化的时候系统会去检测文件中的serialVersionUID,看它是否和当前类的serialVersionUID一致,如果一致就说明序列化的类的版本和当前类的版本是相同的,这个时候可以成功反序列化,否则就说明当前类和序列化的类相比发生了某些变换.

  • 静态成员变量属于类不属于对象,所以不会参与序列化过程
  • 其次用transient关键字标记的成员变量不参与序列化过程
  • 要重写writeObject、readObje可以改变序列化过程
方法 功能 标记位
createFromParcel(Parcel in) 从序列化的对象中创建原始对象
newArray[int size] 创建指定长度的原始对象数组
User(Parcel in) 从序列化的对象中创建原始对象
write ToParcel(Parcel out, int flags) 将当前对象写入序列化结构中,其中flags标识有两种值0或1(参见右侧标记位)。为1时标识当前对象需要作为返回值返回,不能立即释放资源,几乎所有情况都为0 PARCELABLE_WRITE_RETURN_VALUE
describeContents 返回当前对象的内容描述。如果含有文件描述符,返回1(参见右侧标记位),否则返回0,几乎所有的情况都返回0 CONTENTS_FILE_DESCRIPTOR

Binder

继承IBinder,是一种跨进程通信方式,是ServiceManager连接各种Manager(ActivityManager,WindowManager等)和相应ManagerService的桥梁,从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务器会返回一个包含了服务器端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者是数据,这里的服务包含了普通服务和基于AIDL的服务。

首先,当客户端发起远程请求时,由于当前线程会被挂起直至服务端进程返回数据,所以如果一个远程方法是很耗时的,那么不能在UI线程发起此远程请求;其次,由于服务端的Binder方法运行在Binder的线程池中,所以不管Binder是否耗时都应该采用同步的方式去实现,因为它已经运行在一个线程中了。

Binder两种重要的方法

如何给Binder设置死亡代理

1、声明一个DeathRecipient对象、DeathRecipient是一个接口,其内部只有一个方法bindDied,实现这个方法就可以在Binder死亡的时候收到通知了。

private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
    @Override
    public void binderDied() {
        if (mRemoteBookManager == null) return;
        mRemoteBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
        mRemoteBookManager = null;
        // TODO:这里重新绑定远程Service
    }
};

2、在客户端绑定远程服务成功之后,给binder设置死亡代理

mRemoteBookManager.asBinder().linkToDeath(mDeathRecipient, 0);

Android的IPC方式

Bundle实现了Parcelable接口,Activity、Service和Receiver都支持在Intent中传递Bundle数据

这种方式简单,适合在对数据同步要求不高的进程之间进行通信,并且要妥善处理并发读写的问题,SharedPreferences是一个特例,虽然它也是文件的一种,但是由于系统对它的读写有一定的缓存策略,即在内存中会有一份SharedPreferences文件的缓存,因此在多进程模式下、系统对它的读写就变的不可靠,当面对高并发读写访问的时候,有很大几率会丢失,因此,不建议在进程间通信中使用SharedPreferences。

使用Socket

套接字,分为流式套接字和用户数据报套接字两种,分别对应于网络的传输控制层中TCP和UDP协议。

Binder连接池

上一篇 下一篇

猜你喜欢

热点阅读