《Android开发艺术探索》读书笔记----第二章:Android(安卓)IPC 简介、多进程模式
Android IPC 简介
- 定义
IPC 是 Inter-Process Communication 的缩写,含义为进程间通信或者跨进程通信,是指两个进程之间交换数据的过程。- 进程和线程
根据操作系统的描述,线程是CPU调度的最小单元,同时线程是一种有限的系统资源。进程一般指一个执行单元,在PC和移动设备上指一个程序或者一个应用。一个进程可以包含多个线程,因此,进程和线程是包含与被包含的关系。在Android里面,主线程也叫UI线程,在UI线程里面才能操作界面元素。- ANR异常(Application Not Responding)
如果一个进程要执行大量的耗时任务,如果把这些任务放在主线程中去执行就很容易造成界面无法响应,即应用程序无响应,ANR异常。
IPC 不是 Android 所特有的,任何一个操作系统都需要有响应的 IPC 机制,比如 Windows 上可以通过剪贴板、管道、邮槽等来进行进程间通信。Linux 上可以通过命名管道、共享内存、信号量等来进行进程间通信。不同的操作系统有不同的进程间通信的方式,对于 Android 来说,它是一种基于 Linux 内核的移动操作系统,也有自己的进程间通信的方式。在 Android 中最有特色的进程间通信方式就是 Binder 了,通过 Binder 可以轻松的实现进程间通信,还有 Socket ,通过 Socket 也可以实现任意两个终端之间的通信,当然,同一个设备上的两个进程也可以通过 Socket 通信。
- 多进程的情况分为两种:
1.一个应用因为某些原因需要采用多进程模式来实现,如某些模块由于特殊原因需要运行在单独的进程中、为了加大一个应用的内存所以通过多进程来获取多份内存空间。Android 对单个应用可使用的最大内存空间做了限制,早期可能是16MB,不同设备情况不同。
2.当前应用要向其他应用获取数据,由于是两个应用所以必须采用多进程间通信,使用系统的 ContentProvider 去查询数据时其实也是一中进程间通信。
Android 中的多进程模式
通过给 Android 的四大组件设置 android:process 属性,我们可以轻易地开启多进程模式,但是使用过程中往往会出现许多未知的错误。
- 开启多进程模式
Android 中的多进程是指一个应用中多个进程的情况,因此这里不讨论两个应用之间的多进程情况。
在Android 中使用多进程只有一种方法,那就是给四大组件在 Menifest文件中指定 process 属性,我们无法给一个线程或者实体类指定其运行时所在的进程。另一种非常规的方法:通过JNI在 native 层去 fork 一个新的进程,属于特殊情况。
<activity android:name=".SecondActivity" android:process="com.gechao.test.one" /> <activity android:name=".ThirdActivity" android:process=":one" />
当着两个 Activity 启动时,系统会分别为它们创建一个进程,加上一个默认的进程,就有三个进程,默认的进程名是包名,可以在DDMS中查看进程信息。
上边指定进程时出现了两种写法:
- 第一种是完整的写法,com.gechao.test.one
- 第二种是省略的写法,结果为:com.gechao.test:one 即 在:前边加上完整包名
- 区别
以 : 开头的进程属于当前应用的私有进程,其他应用和组件不可以和它跑在同一个进程中
而第一种写法的进程属于全局进程,其他应用可以通过ShareUID 方式和它跑在同一个进程中。
多进程模式的运行机制
当应用开启多进程之后会出现很多奇怪的现象。
假如我们添加一个 Activity 为 SecondActivity,指定一个新的进程,同时新建一个类,里面存放有一个 public 的静态变量,
public class Manager { public static int Uid = 1;}
- 然后在MainActivity 的 onCreate方法中修改 Uid的值为2,然后启动 SecondActivity,打印 Uid的值,会发现 Uid的值还是1,按照正常逻辑,静态变量是在所有地方共享的,并且每一处的修改都会同步,正常的理解,Uid的值应该已经被改为2。
- 此问题出现的原因是 SecondActivity 运行在一个单独的进程中,我们知道,Android 为每一个应用分配一个独立的虚拟机,或者说为每一个进程分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址,这导致在不同的虚拟机中访问同一个类的对象会产生多份副本,拿本例来说,有一个默认的进程,即进程名为包名,SecondActivity 有一个单独的进程,两个进程都存在一个 Manager 类,并且这两个类互不干扰,在同一个进程中修改 Uid的值只会影响当前进程,不会对其他进程造成影响。
所有运行在不同进程中的四大组件,只要它们之间需要通过内存来共享数据,都会失败,这也是多进程带来的主要影响。正常情况下,四大组件不可能不通过一些中间层来共享数据,那么通过简单的指定进程名都会无法正常运行。当然,某些特殊情况下,某些组件之间不需要共享数据,可以直接通过在 Menifest 中指定进程名来实现多进程,但是这种场景不常见。
一般来说,使用多进程会带来以下的问题:
- 静态成员和单例模式完全失效。
- 线程同步机制完全失效。
- SharePreferences 的可靠性下降。
- Application会多次创建。
第一个问题已经分析完毕,第二个问题其实和第一个是类似的,既然不是一块内存了,那么不管是锁对象还是锁全局类都无法保证线程同步,因为不同进程锁的不是同一个对象。第三个是因为 SharePreferences 不支持两个进程同时去执行写操作,否则会导致一定几率的数据丢失,因为 SharePreferences 底层是通过读写XML文件实现的,并发写显然是容易出现问题的,甚至并发读/写都会出现问题。第四个问题:当一个组件跑在一个新的进程中的时候,由于系统要在创建新的进程的同时分配独立的虚拟机,所以这个过程 其实就是启动一个应用的过程,因此系统又把这个应用重新启动一遍,当然会自动创建新的 Application 。运行在同一个进程中的组件属于同一个虚拟机和同一个 Application 的,在不同进程中的组件是属于不同的 虚拟机和 Application 的,可以在 Application 的onCreate方法中做测试。
这里我们分析了多进程带来的问题,但是我们不能因为多进程有很多问题就不去使用,为了解决这个问题,系统提供了很多跨进程通信的方法,虽然不能直接共享内存,但是跨进程通信我们还是可以实现数据交互,实现跨进程通信的方式有很多,接下来会一一介绍。
更多相关文章
- Android(安卓)App开发之ANR异常的原因分析及处理总结
- Android面试整理
- Android学习笔记_23_服务Service之AIDL和远程服务实现进程通信以
- Android游戏的基础:物体运动效果
- android handler,looper,messageQueue重点记录
- Android中实现并发性联网和数据访问
- android进程间通讯(2)--Binder解析及AIDL的使用
- Android进程详解
- Android(安卓)并发二三事之Java线程池