当前位置:   article > 正文

Android IPC机制之开启多进程模式_启用多进程模式是什么

启用多进程模式是什么

            IPC是Inter-Process Communication的简写,意为进程间通信或者跨进程间通信,是指两个进程间进行数据交换的过程。在说道进程间通信,首先,我们要理解什么是进程?什么线程?进程跟线程的关系又是什么?搞清楚这些东西,对我们来说,是很有必要的,当然了,这个进程与线程的关系,你们肯定是知道的,但是我还是要在这里啰嗦两句,哈哈,不要喷我啊。首先来说,什么是线程?线程其实就是程序中单独执行的流控制。那么什么又是多线程呢?那么他呢其实就是单个程序中,可以同时运行多个不同线程执行不同的任务。多线的作用就是最大限度的使用CPU资源。而进程呢?一般指的是一个执行单元。比如:一个程序或者在Android上来说,它是一个应用。进程可以有多个线程,所以说,进程与线程是包含与被包含的关系。

           那么我们为什么要知道这个多进程呢?多进程对我们来说又有什么好处呢?这个多进程的使用场景很多,我们知道在Android早些时候的版本,每个应用分配的内存大小是16MB,有时候,我为了解决这个应用内存大小的问题,我就采用了多进程来解决这个内存不足的问题。当然,还有很多使用场景,比如说还有我们比较常见的跨进程通讯,ContentProvider对吧,他也是一种跨进程通信。好了,既然说到了多进程,那么我们下面就来说说如何开启多进程?当然开启多进程很简单,我们给四大组件定义一个process属性,就好了。但是,开启多进程对我们来说真的很简单吗?答案是否定的,如果多进程应用的不好,那就犹如黄河之水泛滥一发不可收拾。如果控制的不好,将会给你的程序带来灾难性的后果。下面我们来看个例子,然后来分析分析,在开启多进程之后会带来那些问题。如下:



我们在清单文件里配置,如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest
  3. package="com.example.ipcdemo"
  4. xmlns:android="http://schemas.android.com/apk/res/android">
  5. <application
  6. android:allowBackup="true"
  7. android:icon="@mipmap/ic_launcher"
  8. android:label="@string/app_name"
  9. android:supportsRtl="true"
  10. android:name=".MyApplication"
  11. android:theme="@style/AppTheme">
  12. <activity android:name=".MainActivity">
  13. <intent-filter>
  14. <action android:name="android.intent.action.MAIN"/>
  15. <category android:name="android.intent.category.LAUNCHER"/>
  16. </intent-filter>
  17. </activity>
  18. <activity
  19. android:name=".SencondActivity"
  20. android:label="@string/app_name"
  21. android:process=":remote">
  22. </activity>
  23. <activity
  24. android:name=".ThirdActivity"
  25. android:label="@string/app_name"
  26. android:process="com.example.ipcdemo.remote">
  27. </activity>
  28. </application>
  29. </manifest>
好,现在我们运行一下程序,看看:

在上面的清单文件中,我们会发现,我们SencondActivity与ThirdActivity所声明的process方式是不一样的?一个是“  :remote”,一个是加上全部包名,“com.example.ipcdemo.remote”,那么他们之间有什么区别呢?当然是有区别的,对于,ThirdActivity中的声明方式,它是一个i额完整的声明方式,并且它不会附加包名信息,而SencondActivity则会附加包名信息。如果是以“:”开头的进程属于当前应用的私有进程,其他应用组件不可以和它跑到一个进程里,如果不是以“:”开头的进程属于全局的进程,其他的应用可以通过ShareUID可以和它跑到同一进程当中,我们知道Android系统会为每个应用分配一个唯一的UID,相同应用的UID的应用才能共享数据。但是这里要讲明的是,如果两个应用通过SharedUID跑到同一个进程中需要这两个应用的SharedUID相同并且签名也要相同才可以。当然,在这种情况下,他们可以互相访问对方的私有数据,比如:data目录,组件信息等,不管它们是否是跑在同一个进程当中,还有就是它们如果跑在同一个进程当中的话,除了能访问data目下、组件信息,还可以共享内存信息。

         之前我们说道,开启多进程,会出现各种奇奇怪怪的问题,那么下面我们就来看一下这个例子,比如我们创建一个UserManger类,里面声明userId,int类型的:

  1. /**
  2. * Author : Created by rookie
  3. */
  4. public class UserManager {
  5. public static int sUserId = 1;
  6. }
接下来,我们在MainActivity里,修改这个值,然后在打印,接着在SecondActivity里打印一下userId的值,看看他是不是我们之前在MainActivity里面改过来的数据。代码如下:

  1. //MainActivity:
  2. public class MainActivity extends AppCompatActivity {
  3. private static final String TAG = "MainActivity";
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main);
  8. UserManager.sUserId = 2;
  9. Log.d(TAG,"sUserId = "+UserManager.sUserId);
  10. Intent intent = new Intent(this,SencondActivity.class);
  11. startActivity(intent);
  12. }
  13. }
  14. //SencondActivity:
  15. public class SencondActivity extends AppCompatActivity {
  16. private static final String TAG = "SencondActivity";
  17. @Override
  18. protected void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.activity_sencond);
  21. Log.d(TAG, "sUserId = " + UserManager.sUserId);
  22. Intent intent = new Intent(this,ThirdActivity.class);
  23. startActivity(intent);
  24. }
  25. }



又上图可知,他们打印出来的值居然不一样,我们明明在MainActivity里改了,可是值在SedondActivity里打印出来并没有发生改变,这又是为什么呢?我们带着这个问题,来分析解答一下:

出现上述问题的原因很简单,那就是Android为我们每个应用都分配一个独立的虚拟机,或者你也可以这么去理解,Android系统为我们每个进程都分配了一个独立的虚拟机,不同的虚拟机将导致分配的内存空间也不一样,这也就是,在开启多进程的时候,每个进程对应一个独立的虚拟机,并且在访问同一个类的对象时,会产生多个副本。就拿这个例子来说吧,SedondActivity和ThirdActivity这两个进程中都会存在一个UserManger类,并且这两个类还是互不干扰的,那么你在前者的进程中修改值,在后一个进程中是不会收到影响的。这只是其中一种,那么我们在使用多进程的时候,他可能还会带来以下几个问题:

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

2>线程同步机制完全失效。

3>SPreferences的可靠性下降。

4>Application会创建多次。

第一、第二个问题,类似,既然都不在同一个内存块了,无论你是锁对象还是所类都将无法保证线程同步,因为不同进程锁的对象不同。第三个问题,它不支持两个进程同时进行读写操作,否则会导致数据一定机率的丢失,好,到了第四个问题,我们创建一个Applictaion的子类来测试一下,代码如下:

  1. public class MyApplication extends Application {
  2. private static final String TAG = "MyApplication";
  3. @Override
  4. public void onCreate() {
  5. super.onCreate();
  6. Log.d(TAG,"进程名字 : "+ Utils.getProcessName(getApplicationContext(),android.os.Process.myPid()));
  7. }
  8. }
工具类:

  1. public class Utils {
  2. public static String getProcessName(Context context,int processId){
  3. ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
  4. for(ActivityManager.RunningAppProcessInfo appProcess : am.getRunningAppProcesses()){
  5. if(appProcess.pid == processId){
  6. return appProcess.processName;
  7. }
  8. }
  9. return null;
  10. }
  11. }
运行效果:



从上面的结果,我们可以证实,不同进程的组件的确会拥有独立的虚拟机、Application以及内存空间,对吧,这也无形给我们日常开发中带来非常大的困扰,这篇我们说了,在使用多进程时所带来的问题,既然有问题,我们不能视若无睹,当然要想办法去解决,当然,Android系统,为我们提供很多跨进程的通信方式,虽然不能直接共享内存,但是交换数据还是没问题的。那么通信方式有哪些呢?这里可以预告一下,我们将会在下一篇讲到。比如:Intent来传递数据,共享文件和SharedPreferences,基于Binder的Messager和AIDL以及Socket,当然还有内容提供者(ContentProvider),但是,为了让我们更好的理解IPC的通信方式,我们要熟悉一些基础概念,比如:Serializable和Parcelable接口,以及Binder概念。我们将会在下一篇讲到这些基础概念,以及一种IPC机制通信方式。未完待续......


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/510557
推荐阅读
相关标签
  

闽ICP备14008679号