进程与线程
在学习多进程之前有必要了解下进程与线程的区别以及相关的概念, 线程是 CPU 调度的最小单元, 同时线程是一种有限的系统资源, 而进程指一个执行单元, 在 PC 或者移动设备上进程一般指一个程序或者一个应用, 进程包含线程, 所以进程与线程之间是包含与被包含的关系, 在最简单的情况下一个进程只包含一个线程, 在 Android 中则对应着主线程, 也可以称之为 UI 线程, 只有在 UI 线程中才可以执行更新 UI 操作, 如果在 UI 线程中执行大量的耗时操作则可能会引发 ANR 异常既应用无响应.
如何在 Android 中开启多进程
在 Android 中可以通过给四大组件指定 Android:process 属性来轻松的开启进程, 当然也只有四大组件可以指定 process 属性, 例如我们定义了三个 Activity , 并希望它们运行在不同的进程中, 只需要如下的操作就可以了.
- <activity Android:name=".blog.FirstActivity">
- <intent-filter>
- <action Android:name="android.intent.action.MAIN" />
- <category Android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity Android:name=".blog.SecondActivity" Android:process=":remote"/>
- <activity Android:name=".blog.ThirdActivity" Android:process="com.example.tengfei.androidcrossprocess.blog.ThirdActivity"/>
其中 FirstActivity 是入口 Activity , 在 FirstActivity 中启动 SecondActivity , 在 SecondActivity 中启动 ThirdActivity , 执行 adb shell ps | grep com.example.tengfei.androidcrossprocess 来查看相关的进程信息,"com.example.tengfei.androidcrossprocess" 是包名可以用来过滤.
- $ adb shell ps | grep com.example.tengfei.androidcrossprocess
- u0_a179 14313 347 786140 55888 sys_epoll_ 00000000 S com.example.tengfei.androidcrossprocess
- u0_a179 14377 347 783036 52560 sys_epoll_ 00000000 S com.example.tengfei.androidcrossprocess:remote
- u0_a179 14398 347 791116 51040 sys_epoll_ 00000000 S com.example.tengfei.androidcrossprocess.blog.ThirdActivity
可以看到这三个 Activity 分别跑在不同的进程中, 但它们的进程名还是有差异的, 如果没有显式的指定 process 属性, 那么该组件跑在默认进程中, 默认进程名就是包名, 以 ":" 开头的表示该进程是应用的私有进程, 其它应用的组件不可以和它跑在同一个进程中, 其进程名称是包名加 ":[你指定的进程名]", 不以 ":" 开头的是全局进程, 其它应用可以通过 ShareUID 的方式来和它跑在同一个进程中, 刚开始我不太理解, 不同进程怎么跑在同一个进程里? 但实际上是我理解错误了, 应该是不同的组件可以跑在同一个进程里.
在 Android 中系统会为每一个应用分配一个唯一的 UID, 只有相同 UID 的应用才可以共享数据, 只有两个应用具有相同的 ShareUID 并且签名相同才可以跑在同一个进程中, 如果跑在同一个进程中, 那么它们不仅可以共享数据还可以共享内存数据.
一些注意点
1, 静态成员和单例模式完全失效
系统每一个进程分配了一个独立的虚拟机, 在不同进程中访问同一个类的对象实际上是访问的这个类在不同进程的不同副本对象, 既然访问的对象都不一样了, 又怎么可以通过内存来共享数据呢?? 所以说在一个进程中对这个类的对象进行的任何操作都不会影响到另一个进程, 当然进程间通讯就是两码事了.
2, 线程同步机制完全失效
既然在针对同一个类不同进程中有不同的副本有怎么能保证锁住的是同一个对象呢? 不同进程锁住的是不同对象, 这也就没法保证线程同步了.
3,SharePreference 可靠性下降
SharePreference 不支持多个进程并非去执行读写操作, 否则会有一定机率导致数据丢失, 而且并发读写文件的行为本身也不值得推荐呀.
4,Application 会多次创建
在创建新的进程时, 系统会为新的进程分配独立的虚拟机, 这个过程实际上也就是新启动一个应用的过程, 既然是新启动一个应用那么自然 Application 会被多次初始化.
在多进程模式中, 不同进程的组件会拥有独立的虚拟机, Application 以及内存空间, 可以这么理解一个应用中的多进程: 相当于两个不用的应用采用了 ShareUID 的模式.
什么是 ShareUID ?
前面记录了这么多多进程的一些概念, 那么具体什么是 ShareUID 呢? 在 Android 里面每个 App 都有一个唯一的 Linux user ID, 则这样权限就被设置成该应用程序的文件只对该用户可见, 只对该应用程序自身可见, 而我们可以使他们对其他的应用程序可见, 这会使我们用到 SharedUserId, 也就是让两个 apk 使用相同的 userID, 这样它们就可以看到对方的文件. 为了节省资源, 具有相同 ID 的 apk 也可以在相同的 Linux 进程中进行 (注意, 并不是一定要在一个进程里面运行), 共享一个虚拟机.
参考资料
1, Android ShareUserId 使用总结 https://www.cnblogs.com/mythou/p/3258715.html
2,《Android 开发艺术探索》
来源: http://www.jianshu.com/p/ddd91de670f0