IPC,含义为进程间通信或者是跨进程通信,是指两个进程之间进行数据交换的过程,那么线程和进程之间有什么区别呢?
其实线程与进程是两个截然不同的概念,按照操作系统的概念,线程是CPU调度最小的单元,一个进程可以包含多个线程,因此进程和线程之间是包含和被包含的关系。
IPC不是android所独有的,任何一个操作系统都有不同的IPC机制,比如Windows中的剪切板,linux中的管道等等,对于android来说,他是一种基于linux内核的移动操作系统,他的进程间通信不能完全继承自linux,在android中最有特色的进程间通信方式就是Binder了,通过Binder可以轻松的实现跨进程间通信,除了Binder,android还支持Socket,通过Socket也可以实现两个进程间的通信。说到IPC,就必须提到多进程,只有在面对多进程的情况下,才需要考虑进程间通信,多进程的情况分为两种,一种是由于自身的原因需要通过采用多进程实现,有些模块由于特殊的原因需要运行在单独的进程当中,又或者是为了加大内存而需要多进程来实现,android早期的版本可能是16M,另一种情况是当前的应用可能需要获取其他应用的数据,甚至系统提供了ContentProvider去查询数据,其实也是一种跨进程的方式,只是底层的细节被系统隐蔽掉了,我们无法感知。
现在我们来了解下android怎么实现多进程?
android的四大组件,通过指定android:process属性,就可以轻易的开启多进程,但是在实际的使用过程中,我们需要注意开启多进程对代码产生的影响。下面我们来介绍一下2中方法来开启多进程。
1:android:process=”:remote”,他表示开启了一个进程,他是一个私有的进程, 其他的应用的组件不能和他跑在同一个进程之中。
这里说明一下,两个应用需要共享数据,需要这两个应用有相同的shareUid和相同的签名,这种情况下,他们可以访问相互的数据,如data,还可有共享内存中的数据。或者说看起来像是应用的两个部分。
当开启了多进程的模式之后,各种奇怪的现象就会产生,比如说,创建一个静态的变量。
public class Constant{
public static int userId = 1;
}
同时创建两个activity,名字分别为FirstActivity和SecondActivity,他们运行在不同的进程中,在FirstActivity的onCreate方法中把userId赋值为2,然后跳转到SecondActivity,在SecondActivity的onCreate方法中打印userId,我们认为这个userId是2,但是当打印出来的时候,我们看到实际打印出来的是1,那为什么呢,其实这就是多进程产生的原因。
因为SecondActivity运行在一个单独的进程当中,我们知道每个应用都分配一个独立的虚拟机,或者说为每个进程单独的分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的内存地址,这就导致不同的虚拟机访问同一个类的对象会产生多个副本,也就是说SecondActivity和FirstActivity都存在一个Constant,这两个类是互不干扰的,这就是为什么打印出来的两个userId不一样。
所有运行在不同进程中的四大组件,只要他们之间需要通过内存来共享数据,都会失败,这就是多进程带来的影响,正常情况下,我们是不同通过简单的指定android:process来共享数据。
一般情况下,使用多进程,会造成一下的问题:
1:静态成员和单例模式完全失效。
2:线程同步机制是失效。
3:sharedPreferences的可靠性降低。
4:application会创建多次。
第一个上面已经说过,
第二个本质是因为他们不在同一块进程当中,那么不管锁全局类还是其他的都不能保证线程同步,
第三个是因为sharedPreferenced不支持不同的进程去执行写操作,否则会导致几率的失败。
第四个是因为在不同的进程中,创建新的进程会分配独立的虚拟机,所以这个过程其实是启动了一个新的应用,因此,相当于系统重新启动,既然重新启动,当然会创建application,我们可以运行几个不同进程的Activity,然后在application中打印log,我们可以看到打印了多次,这就说明多进程模式下,会产生多个application,也就是不同的进程会拥有独立的虚拟机,application和内存空间,这会给开发带来很大的困扰。
为了解决这个问题,系统提供了多种跨进程的方式,虽然不能直接共享内存,但是可以通过跨进程来实现数据的交互,比如intent,Messager和Aidl。