开启多进程模式
Android中多进程是指一个应用中存在多个进程的情况,在Android中使用多进程只有一种方法,就是给四大组件在AndroidManifest.xml中指定android:process属性,除此之外没有其它办法。
<activity
android:name="com.demo.ipc.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.demo.ipc.TestActivity"
android:launchMode="singleTask"
android:process=":test">
</activity>
<activity
android:name="com.demo.ipc.AnotherActivity"
android:process="com.demo.ipc.another">
</activity>
在上面的示例中,启动TestActivity时,系统会为它创建一个单独的进程,进程名为“com.demo.ipc:test”,当启动AnotherActivity时,系统会为它创建一个单独的进程,进程名为“com.demo.ipc.another”,由于没有给入口的MainActivity指定process属性,所以它运行在默认进程中,默认的进程名就是应用的包名。
可以通过 adb shell ps 或者 adb shell ps | grep com.demo.ipc 来查看进程信息。
在上面的示例种指定process属性的方式有两种,一种是“:test”,一种是“com.demo.ipc.another”,这两种的区别在于以“:”开头的指定方式会在当前指定的进程名前面附加上当前的包名,属于当前应用的私有进程,其它应用的组件不可以和它跑在同一个进程中。
而不以“:”开头的指定方式是一种完整的命名方式,不会附加包名信息,属于全局进程,其它应用可以通过ShareUID方式和它跑在同一个进程中。但是,两个应用通过ShareUID跑在同一个进程中是有要求的,需要这两个应用有相同的ShareUID并且签名相同才可以,在这种情况下,他们可以互相访问对方的私有数据。
多进程模式的运行机制
开启多进程模式很简单,只需要在AndroidManifest.xml中指定android:process属性就可以了,但是开启了多进程模式后,各种奇怪的问题就出现了,下面来看一个示例。
首先创建一个实体类,这个实体类中只有一个公共的静态成员变量,如下:
public class User {
public static int userId = 1;
}
然后在MainActivity的onCreate()方法中将userId的值修改为2:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
userId = 2;
}
然后在MainActivity中启动TestActivity,在TestActivity的onCreate()方法中打印userId的值:
2019-12-18 15:24:02.798 17504-17504/? D/TestActivity: userId = 1
发现并不是我们预期的结果打印2,userId的值还是1。这说明多进程的运行并不是我们想象中那么简单。
出现这个问题的原因是因为TestActivity运行在一个单独的进程中,Android为每一个进程都分配了一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这就导致在不同的虚拟机中访问同一个类的对象会产生多个副本,这些副本是互不干扰的,在一个进程中的修改只会影响当前进程,对其它进程不会造成任何影响。
一般来说,使用多线程会造成以下几个方面的问题:
- 静态成员和单例模式完全失效。
- 线程同步机制完全失效。
- SharedPreferences的可靠性下降。
- Application会多次创建。
下面来看一下第四个问题,在Application的onCreate()方法打印当前进程的名字,代码如下:
public class IPCApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
String processName = getProcessName(getApplicationContext(), android.os.Process.myPid());
if (processName != null) {
Log.d("=======processName", processName);
}
}
//获取当前的进程名
private String getProcessName(Context context, int pid) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
if (runningApps == null) {
return null;
}
for (ActivityManager.RunningAppProcessInfo info : runningApps) {
if (info.pid == pid) {
return info.processName;
}
}
return null;
}
}
在同一个应用中启动3个不同进程的Activity,Log如下:
2019-12-18 15:51:56.046 18252-18252/com.demo.ipc D/=======processName: com.demo.ipc
2019-12-18 15:52:06.320 18277-18277/com.demo.ipc:test D/=======processName: com.demo.ipc:test
2019-12-18 15:52:11.120 18299-18299/com.demo.ipc.another D/=======processName: com.demo.ipc.another
通过Log可以知道,Application执行了三次onCreate()方法,这说明当一个组件启动在一个新的进程中的时候,系统在创建新的进程的同时分配独立的虚拟机,这个过程其实就是启动一个应用的过程。这也证实了在多进程模式中,不同进程的组件的确会拥有独立的虚拟机、Application以及内存空间。
关于多进程模式的介绍就到这里了。参考书籍《Android开发艺术探索》。