IPC机制总结

IPC机制

进程间通信

  • 进程和线程
    • 线程是CPU调度的最小单元,同时线程是一种有限的系统资源。
    • 进程一般指一个执行单元,在PC和移动设备上指一个程序或者一个应用。一个进程可以包含多个线程。
  • 多进程情况
    • 一个应用出自某些原因采用多进程模式实现,比如希望通过多进程获取多份内存空间。
    • 当前应用需要向其他应用获取数据。
    • 某些模块有运行在单独进程中的需要。
  • Android中的进程间通信方式
    • Binder实现进程间通信
    • Socket实现任意两个终端之间的通信或者一个设备上的两个进程间的通信。

Android中的多进程模式

  • 开启多进程模式

    • 给四大组件在AndroidMenifest中指定android:process属性。
    • 非常规:通过JNI在native层去fork一个新的进程。
  • 多进程模式的运行机制

    多进程绝非仅仅是指定一个android:process属性那么简单。一般来说,使用多进程会造成以下一个方面的问题

    1. 静态成员变量和单例模式完全失效。
    2. 线程同步机制完全失效。
    3. SharedPreferences的可靠性下降。
    4. Application会多次创建。

    因为Android为每个应用/进程分配了独立的虚拟机,不同的虚拟机在内存分配上占有不同的地址空间,就导致了不同虚拟机中访问同一个对象会产生多分副本。所有运行在不同进程中的四大组件,只要通过内存来共享数据都会失败,这也是多进程带来的主要影响。

    为了解决这些问题,系统提供了很多跨进程通信方法

IPC基础概念

Serializable和Serializable接口都可以完成对象序列化的过程,序列化是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

  • Serializable接口

    Java提供的一个序列化接口,在类声明中指定一个private static final long serialVersionUID(序列化后的数据中的serialVersionUID只有和当前类的相同才能够正常的被反序列化),采用ObjectInputStream和ObjectOutputStream可以实现序列化。需要注意的是:序列化恢复的对象和原对象内容完全一样,但是两者并不是同一个对象

    serialVersionUID的工作机制:序列化时系统会把当前类的serialVersionUID写入序列化文件或者其它中介中,当反序列化的时候系统又回去检测文件中的serialVersionUID,看他是否和当前类的serialVersionUID一致,如果一致就说明序列化的类的版本和当前版本是相同的,这个时候可以成功反序列化。

    另外,静态成员变量不属于类不属于对象,所以不会参与序列化过程;其次用transient关键字标记的成员变量也不参与序列化过程。

  • Parcelable接口

    实现这个接口,一个类的对象就可以通过Intent和Binder传递。 系统已经为我们提供了许多实现了Parcelable接口的类,可以直接序列化,比如Intent、Bundle、Bitmap等等,同时List和Map也可以序列化,前提是它们里面每个元素都是可以序列化的。

Parcelable和Serializable的比较

Serializable的作用是为了保持对象的属性到本地文件、数据库、网络流以方便数据传输,当然这种传输可以是进程内或者不同进程之间的,Serializable开销很大,在序列化和反序列化当中需要进行大量的I/O操作,效率不高。主要用于数据持久化和网络传输

相较而言,Parcelable是Android中的序列化方式,效率很高,内存开销较小,主要用在内存序列上, 是为了在不同组件间以及不同Android应用间(AIDL)高效传输数据而设计,Parcelable是通过IBinder通信的消息的载体 。将对象序列化到存储设备或者网络传输也是可以的,但是过程较Serializable稍微复杂,而且因为Android不同版本Parcelable可能不同,所以不推荐使用Parcelable进行数据持久化。

  • Binder

    直观来说,Binder是Android中的一个类,它实现了IBinder接口。从IPC的角度看,Binder是Android中一种跨进程通信方式,BInder还可以理解为一种虚拟的物理设备,他的设备驱动是/dev/binder,该通信方式在Linux中没有;从Android Framework的角度说,Binder是ServiceManager连接各种Manager和响应ManagerService的桥梁;从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端可以获取服务端提供的服务或者数据,包括普通服务和基于AIDL的服务。

Android中的IPC方式

  • 使用Bundle

    四大组件中的三大组件Activity、Service、Receiver都是支持在Intent中传递Bundle数据的,由于Bundle实现了Parcelable接口,可以方便地在不同的进程之间传输。

  • 使用文件共享

    由于Android系统基于Linux,使其并发读写文件可以没有限制的进行,但是也必须考虑可能出现的线程安全问题,比较适合对于数据同步要求不高的进程之间通信

    其中,对于SharedPreferences存储来说,系统对它的读写有一定的缓存策略,即在内存中会有一份SharedPreferences文件的缓存,所以再多进程模式下,系统对它的读写就变得不可靠,在并发读写时有很大几率丢失数据,因此不建议在进程间通信时使用。

  • 使用Messenger(略过)

    Messenger可以在不同进程中传递Message对象,轻松实现数据的进程间传递。使用方法很简单,对AIDL做了封装,可以很简便地进行进程间通信。

  • 使用AIDL

    • 服务端创建Service监听客户端的连接请求,然后创建AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现这个AIDL接口即可。
    • 客户端首先需要绑定服务端的Service,绑定成功后将服务端返回的Binder对象转换成为AIDL接口所属的类型,接着就可以调用AIDL中的方法了。
    • AIDL接口的创建与远程服务端Service的实现和客户端的实现、
  • 使用ContentProvider(待补充)

  • 使用Socket

    可以通过Socket来实现进程间的通信,Socket也称为“套接字”,分为流式套接字和用户数据报套接字两种,分别对应了网络传输控制层中的TCP和UDP协议。通过Socket不仅仅能够实现进程间的通信,还可以实现设备间的通信,前提是这些设备之间的IP地址互相可见。

Binder连接池

Binder连接池的主要作用就是将每个业务模块的Binder请求统一转发到远程Service中去执行,从而避免重复创建Service的过程,可以大大提高AIDL的开发效率。

选择合适的IPC方式

选择合适的IPC方式完成多进程的开发场景。

名称 优点 缺点 适用场景
Bundle 简单易用 只能传输Bundle支持的数据类型 四大组件间的进程间通信
文件共享 简单易用 不适合高并发场景,并且无法做到进程间的即时通信 无并发访问情景,交换简单的数据实时性不高的场景
AIDL 功能强大,支持一对多并发通信,支持实时通信 使用稍复杂,需要处理好线程同步 一对多通信而且有RPC(远程过程调用)需求
Messenger 功能一般,支持一对多串行通信,支持实时通信 不能很好地处理高并发情形,不能支持RPC,数据通过Message进行传输,因此只能传输Bundle支持的数据类型 低并发的一对多即时通信,无RPC需求,或者无需要返回结果的RPC需求
ContentProvider 在数据源访问方面功能强大,支持一对多并发数据共享,可以通过Call方法扩展其他操作 可以理解为受约束的AIDL,主要提供数据源的CRUD操作 一对多的进程间数据共享
Socket 功能强大,可以通过网络传输字节流,支持一对多并发实时通信 实现细节稍微繁琐,不支持直接的RPC 网络数据交换
原文地址:https://www.cnblogs.com/chen-ying/p/12259047.html