作为Android开发人员,IPC应该是我们能经常听到的。但是什么是IPC?IPC的使用场景是什么?Android中IPC的实现模式有哪几种?这些一连串的问题,也许对于初学者来说就不那么简单了。接下来,让我们一起去详细了解一下这个常用但并不简单的IPC机制。
IPC是Inter-Process Communication 的简称,翻译过来也就是我们经常提到的跨进程通信。要掌握跨进程通信,我们首先要了解什么是进程,而谈到进程,线程也不可避免的需要了解,这里就放到一起介绍。从操作系统的层面来说,进程是CPU调度的最小的单元。而进程是指一个执行单元,在Android设备中,正常情况下一个进程就是一个应用。一个进程可以包含多个线程,所以说进程和线程的关系是包含和被包含的关系。
什么情况下会出现多进程呢?通常情况下有以下两种情况:第一种情况是单个应用因为某些原因自身需要采用多进程的模式,这个原因可能就比较多了,比如说有些模块由于特殊的原因需要运行在单独的进程中等。第二种情况就是两个不同的应用之间需要进行数据的传递,此时就只能采用跨进程的方式去获取所需的数据了。
Android中开启多进程的方式
在Android中如何开启多进程呢,在Android中只有一种方法去开启多进程,那就是在AndroidMenifest文件中给四大组件(Activity、Service、Receiver、ContentProvider)指定android:process属性。下面举例说明:
<activity
android:name=".Activity1"
android:process=":remote" />
<activity
android:name=".Activity2"
android:process="com.jyn.test.remote" />
上面的代码为Activity1和Activity2都指定了process属性,并且二者的属性值不同,这就意味着当前的应用又启动了两个新的进程。假设软件的包名为com.jyn.test,当软件运行后,系统会为Activity1创建一个单独的进程,进程名为com.jyn.test:remote;为Activity2创建一个单独的进程,进程名为com.jyn.test.remote.而没有指定process的四大组件,则在默认进程中运行,默认进程名为包名(这里就是com.jyn.test)
大家应该都注意到了Activity1 和Activity2的android:progress 属性是有所区别的。Activity1的android:process 属性以“:”开头,而Activity2的则没有,那具体的区别是什么呢:“:”的含义是指要在当前的进程名前面加上当前的包名,这是一种简写,所以Activity1完整的进程名是com.jyn.test:remote;对于Activity2中的声明方式是一种完整的命名方式,不会附加包名信息。还有一点区别就是,以“:”开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中,而进程名不以“:”开头的进程属于全局进程,其他应用是可以和它跑在同一个进程中(通过shareUID的方式)。
开启多进程所引发的问题
从上面的内容中我们不难发现,开启多进程的方法是比较简单的,只需要给四大组件指定android:process属性即可,但实际的开发工作中真的就是如此简单吗?如果直接说多线程的使用并不是如此简单,我相信大多数人都不会信服。那我们还是实践出真理,给一个实际的例子看看,我所说的不仅简单到底体现在什么地方。
新建两个Activity:TestActivity和SecondActivity,然后我们再新建一个类Project,Project 中有一个public类型的静态成员变量,具体代码如下:
public class Project {
public static int SIZE = 1024;
}
随后在TestActivity的onCreate()方法中把SIZE值赋值为2048,在控制台打印这个变量的值,然后启动SecondActivity,在SecondActivity的onCreate()方法中也打印这个变量的值,输出如下。
由上图可知,这个是正常的,因为静态变量是可以在所有地方共享 的,在TestActivity中改变他的值后,在其他地方访问就是改变后的结果了。
这时我们给SecondActivity添加android:process属性,给SecondActivity重新开启一个进程,看看结果会是怎样的呢,经测试,结果如下所示:
11-08 10:09:12.986 15985-15985/com.jyn.test D/TestActivity: 2048
11-08 10:09:20.971 16146-16146/? D/SecondActivity: 1024
从日志中我们可以很明显的看出,结果竟然是1024,可是我们的确已经在TestActivity中把SIZE的值重新赋值了啊。由此可以看出使用多进程并非那么的简单。
我们先解释一下为什么会出现上文中所描述的情况,根本原因我们是知道的,就是因为SecondActivity运行在了另外一个进程中造成的。从系统层面来讲,Android会为每一个进程都分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这就导致在不同的虚拟机中访问同一个类的对象会产生多个副本,就拿上面这个例子来说,在com.jyn.test(默认进程)和com.jyn.test:remote进程中都存在一个Project类,并且这两个类是互不干扰的,在一个进程中修改一个对象的变量值只会影响当前进程,对其他进程是没有影响的,所以才会造成以上的现象。
一般情况下,使用多进程会造成一下几个问题:
1.静态成员和单例模式完全失效。
2.线程同步机制完全失效。
3.SharedPreferences的可靠性下降。
4.Application会多次创建。
既然使用多进程会出现这么多问题,相应的系统也提供了多种跨进程的通信方法,随后我们将进一步的去学习如何进行跨进程的通信。