Android IPC机制(一) Android种的多进程模式

Android IPC简介


IPC是Inter-Process Communication的缩写,含义为进程间通信或者跨进程通信,是指两个进程之间进行数据交互的过程,说起进程间通信,我们首先要理解什么是进程,什么是线程,进程和线程是截然不同的概念,按照操作系统种的描述,线程是CPU调度的最小单元,同时线程是一种有限的系统资源,而进程一般指一个执行单元,在PC和移动设备上指一个程序或者一个应用,一个进程可以包含多个线程,因此线程和进程是包含与被包含的关系,最简单的情况下,一个进程可以只有一个线程,即主线程,在Android 里面主线程也叫UI线程,在UI线程里才能操作界面元素,很多时候,一个进程中需要执行大量耗时的任务,这里这些任务放在主线程中去执行就会造成界面无法响应,严重影响用户体验,这种情况在PC系统和移动系统中都存在,在Android 中有一个特殊的名字叫ANR(Application Not Responding),即应用无响应,解决这个问题就需要用到线程,把一些耗时的任务放在线程中即可。

IPC不是Android 中所独有的,任何一个操作系统都需要有相应的IPC机制,比如Windows上可以通过剪贴板,管道来进行进程间通信:Linux上可以通过命名管道,共享内容,信号量等来进行进程间通信,可以看到不同的操作系统平台有着不同的进程间通信方式,对于Android 来说,它是一种基于linux内核的移动操作系统,它的进程间通信方式并不能完全继承自Linux,相反,它有自己的进程间通信方式,在Android 中最有特色的进程间通信方式就是Binde了,通过Binder可以轻松的实现进程间通信,除了Binder,Android 还支持Socket,通过Socket 也可以实现任意两个终端之间的通信,当然同一个设备上的两个进程通过Socker通信自然也是可以的。

说到IPC的使用场景就必须提到多进程,只有面对多进程这种场景下,才需要考虑进程间通信,这个是很好理解的,如果只有一个进程在运行,又何谈多进程呢?多进程的情况分为两种,第一种情况是一个应用因为某些原因自身需要采用多进程模式来实现,至于原因,可能有很多,比如有些模块由于特殊原因需要运行在单独的进程中,又或者为了加大一个应用可使用的内存所以需要通过多进程来获取多分内存控件。Android 对单个应用所使用的最大内存做了限制,早期的一些版本可能是16MB,不同设备有不同的大小,另一种情况是当前应用需要向其他应用获取数据,由于是两个应用,所以必须采用跨进程的方式来获取所需的数据,甚至我们通过系统提供的ContentProvider去查询数据的时候,其实也是一种进程间通信,只不过通信细节被系统屏蔽了,我们无法感知而已,不管由于何种原因,我们采用了多进程的设计方法,那么应用种就必须妥善地处理进程间通信的各自问题。

Android 种的多进程模式


在正式介绍进程间通信之前,我们必须先要理解Android 种的多进程模式,通过给四大组件指定android:process属性,我们可以轻易的开启多进程模式,这看起来很简单,但是实际使用过程中却暗藏杀机,多进程远远没有我们想的那么简单,有时候我们通过多进程得到的好处甚至都不足以弥补使用多进程所带来的代码层面的负面影响。

开启多进程模式

正常情况下,在Android 种多进程是指一个应用种存在多个进程的情况,因此这里不讨论两个应用之间的多进程情况,首先,在Android中使用多进程至于一种方法,那就是给四大组件(Activity,Service,Receiver,ContentProvider)在AndroidMenifest中指定andorid:process属性,除此之外没有其他办法,也就是说我们无法给一个线程或者一个实体类指定其运行时所在的进程,其实还有另外一种非常规的多进程方法,那就是通过JNI在native层去fork一个新的进程,但是这种方式属于特殊情况,也不是常用的创建多进程的方式,因此我们暂时不考虑这种方式

8656692-705a4c18c747200a.png

上面的示例分别为SecondActivity和ThirdActivity指定了process属性,并且他们的属性值不同,这意味着当前应用有增加了两个新进程,假设当前应用的包名为“com.example”,当SecondActivity启动时,系统会为它创建一个单独的进程,进程名为“com.exampl:remote”,当ThirdActivity启动时,系统也会为它创建一个单独的进程。进程名为“com.demo”,同时入口Activity是MainActivity,那么它运行在默认进程中,默认进程的进程名是包名。

除了在Eclipse的DDMS视图中查看进程信息,还可以用shell来查看,命令为:adb shell ps或者adb shell ps | com.example,其中com.example是包名,我们知道Android系统会为每个应用分配一个唯一的UID,具有相同的UID的应用才能共享数据,这里要说明的是,两个应用通过ShareUID跑在同一个进程中是有要求的,需要这两个应用有相同的ShareUID并且签名相同才可以,在这种情况下,他们可以互相访问对方的私有数据,比如data目录,组件信息等,不管他们是否跑在同一个进程中,当然如果我们跑在同一个进程中,那么除了能共享data目录,组件信息,还可以共享内存数据。

多进程模式的运行机制

所以运行在不同进程中的四大组件,只要他们之间需要通过内存来共享数据,都会共享失败,这也是多进程所带来的主要影响,正常情况下,四大组件中间不可能不通过一些中间层来共享数据,那么通过简单的指定进程名来开启多进程都会无法正确运行,当然,特殊情况下,某些组件之间不需要共享数据,这个时候可以直接指定android:process属性来开启多进程,但是这种场景是不常见的,几乎所有情况都要共享数据/

一般来说,使用多进程会造成如下几个方面的问题:

1 静态成员和单例模式完全失效

2 线程同步机制完全失效

既然都不是一块内存了,那么不管是锁对象还是锁全局类都无法保证线程同步,因为不同进程锁的不是同一个对象

3 SharedPreferences的可靠性下降

SharedPreferences不支持两个进程同时去执行写操作,否则会导致一定几率的数据丢失

4 Application会多次创建

当一个组件跑在一个新的进程中的时候,由于系统要在创建新的进程同时分配独立的虚拟机,所以这个过程其实就是启动一个应用得过程,因此,相当于系统又把这个应用重新启动了一遍,既然启动了那么自然会创建新的Application,这个问题其实可以这么理解,运行在同一个进程中得组件是属于同一个虚拟机和同一个Application的,同理,运行在不同进程中的组件是属于两个不同的虚拟机和Application 的。


为了解决这些问题,系统提供了很多跨进程通信方法,虽然不能直接的共享内存,但是通过跨进程通信我们还是可以实现数据交互,实现跨进程通信的方式很多,必须通过Intent传递数据,共享文件和SharedPreferences,基于Binder的Messenger和AIDL以及Socket等,但是为了更好的理解各种IPC方式,我们需要先熟悉一些基础概念,必须序列号相关的Serializable和Parcelable接口,以及Binder的概念

猜你喜欢

转载自blog.csdn.net/weixin_34283445/article/details/87218692