IPC(上)-多进程入门

1 IPC介绍

既然是IPC的开篇那么先介绍下IPC的定义
IPC:进程间通信或者跨进程通信,即进程间交换数据的过程.
说到进程,那么需要了解下什么是进程.什么是线程,按操作系统描述,线程是CPU调度的最小单元,同时线程是一种有限的系统资源,而进程指一个执行单元,在PC和移动设备上指一个程序或者应用,一个进程可以包含多个线程,因此进程和线程是包含和被包含的关系,

在Android中进程间通信方式就是Binder了,除了Binder还有Socket不仅可以实现进程通信,也可以实现任意终端之间的通信,

IPC在多进程使用情况分为两种:

  • 应用因为某些原因自身需要采用多进程模式来运行,比如某些模块由于特殊原因需要运行在单独的进程中,又或者为了加大一个应用可使用的内存所以需要通过多进程来获取更多内存空间.

  • 应用需要访问其他应用的数据.甚至我们通过系统提的ContentProvider去查询数据的时候,也是一种进程间通信.

总之采用了多进程的设计方法,那么就必须解决进程间通信的问题了.

2 Android中多进程模式

在Android中通过给四大组件指定android:process属性,我们可以轻易的开启多进程模式,但是同时也会带来一个麻烦,下面将会一一介绍

2.1 开启多进程模式

Android中多进程一般指一个应用中存在多个进程的情况,因此这里不讨论两个应用之间的多进程情况,

一般情况下Android中使用多进程只有一个方法,就是给四大组件在AndroidMenifest中指定android:process属性,还有一个非常特殊的方法,就是通过JNI在native层去fork一个新的进程,由于不常用,所以这里只介绍一般情况下的创建方式

下面是一个例子描述如何创建多线程

  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.zly.www.ipc">

      <application
          android:allowBackup="true"
          android:icon="@mipmap/ic_launcher"
          android:label="@string/app_name"
          android:supportsRtl="true"
          android:theme="@style/AppTheme">
          <activity android:name="com.zly.www.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.zly.www.ipc.TwoActivity"
              android:process=":zly"/>

          <activity android:name="com.zly.www.ipc.ThreeActivity"
              android:process="com.zly.www.ipc.zly"/>
      </application>

  </manifest>

这里是三个activity.
MainActivity未指定process所以运行在默认的进程中,而默认的进程名是包名.TwoActivity和ThreeActivity指定了不同的process,所以将会新建两个进程TwoActivity process值为:zly,而”:”的含义指当前进程名为 包名 + “:zly”,是一种简写,所以进程为com.zly.www.ipc:zly. ThreeActivity process值为com.zly.www.ipc.zly所以进程名就是com.zly.www.ipc.zly

其次,进程名以:开头的进程为当前应用的私有进程,其他应用的组件不可以和它跑在同一进程中,而进程名不以:开头的属于全局进程,其他应用可以通过shareUID方式和他跑在同一进程.

这里可以通过ddms工具看出

确实开起了三个进程,但这只是开始,实际使用中多进程还有很多问题需要处理后面将细说

2.2 多进程模式的运行机制

如果用一句话来形容多进程,那么可以这样描述,当应用开启了多进程以后,各种奇怪的现象就都来了,举个栗子,新建一个类User,里面有一个静态成员变量uId如下

public class UserBean {

  public static int uId = 1;

}

其中MainActivity运行在默认进程,TwoActivity通过指定process运行在一个独立的进程中,然后在MainActivity的onCreate()方法中将uId赋值为2,打印出这个变量,再在TwoActivity中打印该值

发现结果和我们平常的所见的完全不同,按正常情况下TwoActivity中uid应该也是2才对,看到这里也就应了前面所说的,当应用开启了多进程以后,各种奇怪的现象就都来了,所以多进程绝非仅仅只是添加一个process属性那么简单.

上述问题出现的原因是TwoActivity运行在一个单独的进程中,而Android为每一个应用分配了一个独立的虚拟机,或者说为每一个进程都分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这就导致在不同的虚拟机中访问同一个类的对象会产生多份副本.拿我们这个例子来说,在TwoActivity所在进程和MainActivity所在进程都存在一个UserBean类,并且这两个类互相不干扰,在一个进程中修改uId值只会影响当前进程,对其他进程都不会造成任何影响,这样就解释了为什么在MainActivity修改uId的值,而在TwoActivity中uId值没有发生改变.

所有运行在不同进程中的四大组件,只要他们之间通过内存来共享数据都会失败,这也是多进程带来的主要影响.一般来说,使用多进程会造成如下几个方面的问题

  1. 静态成员变量和单例模式失效

  2. 线程同步机制完全失效

  3. SharedPreferences的可靠性下降

  4. Application会多次创建

第1个问题上面已经分析了.第2个问题本质和第1个是一个问题,既然都不是一个内存了,那么不管是锁对象还是锁全局类都无法保证线程同步,因为不同进程锁的不是同一个对象.第3个问题是因为SharedPreferences不支持两个进程同时执行操作否则会有数据丢失的可能,第4个问题,当一个组件跑在一个新的进程中的时候,由于系统要在创建新的进程同时分配独立虚拟机,所以这个过程其实就是启动一个应用的过程.因此,相当于系统又把这个应用重新启动了一遍,既然重启了当然会创建新的application,其实可以这么理解,运行在同一个进程的组件是属于同一个虚拟机和同一个application.为了更加清晰的展示着一点,下面我们做个测试,首先在Application的onCreate方法中打印出当前进程的名字,然后连续启动三个同一个应用内但属于不同进程的Activity,按照期望,Application的onCreate应该执行三次,并且打印出来的三次的进程名不同.

public class AppApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        Logger.init("zhuliyuan");

        Logger.d(getCurProcessName(this));
    }

    String getCurProcessName(Context context) {
        int pid =
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值