本文转载自微信公众号「Android开发编程」,作者 Android开发编程。转载本文请联系Android开发编程公众号。
今天来讲解下:多进程通信方式以及带来的问题,方便在项目中遇到问题及时的处理;
一、Android中多进程详解
2、开启多进程
Android中开启多进程只有一种方法,就是在AndroidManifest.xml中注册Service、Activity、Receiver、ContentProvider时指定android:process属性,例如:
- <service
- android:name=".MyService"
- android:process=":remote">
- </service>
- <activity
- android:name=".MyActivity"
- android:process="com.test.remote2">
- </activity>
我们为MyService和MyActivity指定的android:process属性值有所不同,它们的区别如下:
3、Android中的多进程通信方式
多进程通信方式主要有以下几种,它们之间各有优缺点,可根据使用场景选择选择:
二、 多进程带来的问题
1、静态变量失效
在一个Activity中新建一个静态变量TEST_STATIC,并在RemoteActivity1中的onStartOtherRemoteActivity方法中自增,之后启动RemoteActivity2,并在2中打印TEST_STATIC的值;
- public static int TEST_STATIC = 21;
- public void onStartOtherRemoteActivity(View view) {
- TEST_STATIC++;
- Log.e(TAG, "onStartOtherRemoteActivity: " + TEST_STATIC);
- startActivity(new Intent(this, RemoteActivity2.class));
- }
- 结果:
- // RemoteActivity1 log
- E/RemoteActivity1: onStartOtherRemoteActivity: 22
- // RemoteActivity2 log
- E/RemoteActivity2: onCreate: 21
并不相同的数值说明在多进程中静态变量是失效的,同样的因为静态变量带来的问题是单例模式的失效;
原因就是多进程时Android为其他进程分配了一个新的虚拟机,导致不同的虚拟机在内存上有不同的内存地址, 当在新的进程访问变量时,访问的其实是这个类在新的虚拟机中的副本,也就是相当于在:remote和.remote中各有一个RemoteActivity1类,而.remote访问的那个副本中的TEST_STATIC是没有进行自增操作的,所以还是会打印出21的初始数值,而在:remote中是自增过的22;
单例模式也是同样的解释,当在另一个进程中访问单例类时,在此进程中其实并没有进行初始化,所以才会失效;
2、线程同步机制失效
本质上跟静态变量类似,在一个进程锁住的是副本的对象,而在另一个副本中,内存都不同,所以肯定是无效的;
3、SharedPreferences可靠性下降
SharedPreferences不支持两个进程同时去执行写操作,否则会导致一定几率的数据丢失;
SharedPreferences的底层是通过读写XML文件实现的,并发写很可能导致问题,并发读写都不能保证不会出问题;
4、Application会被创建多次
当一个组件跑在一个新的进程中时,系统给新的进程分配一个新的虚拟机,就相当于应用又一次的重新启动,Application作为应用基础肯定也会被重新创建;
新建Application类,继承自Application,并在onCreate方法中输出当前进程的PID:
- public class LApplication extends Application {
- private static final String TAG = "LApplication";
- @Override
- public void onCreate() {
- super.onCreate();
- Log.e(TAG, "onCreate: " + android.os.Process.myPid());
- }
- }
当依次开启进程后输出如下:
- // Main
- E/LApplication: onCreate: 16031
- // RemoteActivity1
- E/LApplication: onCreate: 16127
- // RemoteActivity2
- E/LApplication: onCreate: 16202
Application被创建多次带来的问题是,有些时候会需要在Application中初始化些依赖,但是多进程就会随着Application的创建而重复初始化,可以在Application中设置一些条件跳过重复初始化部分;
- // 根据pid获取进程名
- private String getAppName(int pid) {
- String processName = null;
- ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
- List<ActivityManager.RunningAppProcessInfo> list = am.getRunningAppProcesses();
- for (ActivityManager.RunningAppProcessInfo info : list) {
- try {
- if (info.pid == pid) {
- processName = info.processName;
- return processName;
- }
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
- return null;
- }
通过PID获取进程名,与包名做对比,只有跟包名一致时才做一些初始化工作;
多进程实现今天没有讲,以后会讲解的;
多进程不难的,难的在于要克服困难,战胜自己;