Android01_必知必会Android知识整理Android知识

一次搞定Process和Task

2016-10-18  本文已影响1541人  黄怡菲

关于进程-Process

影响process的属性

控制组件运行进程的有两个属性:android:processandroid:multiprocess

关于android:process

只有provider和activity定义了android:multiprocess,但不要在activity中使用。

如果android:multiprocess为true,则每个访问provider的应用都会自己创建一个ContentProvider实例

如果需要两个不同APK中的组件运行于同一个进程,需要以下三个条件:

不同Process带来的影响

跨进程通信

由于不同的进程使用不同的内存空间,所以不同进程之间的通信本质上只依赖以下四种方式

ContentProvider的实现就是使用ASHMEM

进程优先级

内存不足时,系统可能杀掉进程,这时进程中的Application和应用组件也会随之销毁。系统如何选择停止的进程,就涉及到进程优先级了。

  1. 前台进程 Activte process
    • 前台响应用户事件的Activity以及与之绑定的Service
    • startForeground的Service
    • 正在执行onStart,onCreate,OnDestroy的Service
    • 正在执行onReceive的BroadcastReceiver
  2. 可见进程 Visible Process
    • onPause但未onStop的Activity
    • 绑定到可见Activity的Service
  3. 服务进程 Service process
    • 普通Service
  4. 背景进程 Background process
    • onStop的Activity
  5. 空进程 Empty process
    • 不包含任何组件的进程

Process的实际使用

  1. 子进程可以分担主进程的内存压力
  2. 在主进程Crash时,子进程中的功能不受影响
  3. 子进程的Application#onCreate中可以跳过一些不必要的初始化

关于任务-Task

关于Task,有太多的参数与之相关,而且他们相互影响,感觉无法穷尽。下面仅从实际的使用出发,明确和Task相关的一些原则。

Task和startActivityForResult

使用startActivityForResult的必要条件是被启动的Activity和原Activity要在同一个Task中。因此,使用startActivityForResult时,会强制将新启动的Activity放在原来的Task中,不论activiy的xml属性和Intent#Flag_XXX

只有一个例外FLAG_ACTIVITY_NEW_TASK:如果使用这个标签,原Activity会立刻收到onActivityResult,并执行和startActivity相同的逻辑。在后面的分析中可以看到,仅凭这个FLAG是无法正真启动新Task的。

多Task有关的参数

可以下载多Task相关的演示代码,修改MultiTaskActivity启动方法的Intent和Manifest中的属性,就可演示这小结的大部分例子。

launchMode

  1. standardsingleTop:可以包含多个Activity实例
  2. singleInstancesingleTask:只有一个Activity实例
  3. singleInstance是一个Task中唯一的Activity
  4. singleTask不一定是Task root(google文档有问题,但使用中建议作为Task root使用)

taskAffinity

  1. 仅有singleInstance启动新Task不依赖taskAffinity
  2. singleTask的Activity只有其taskAffinity和原Activity不一样时才会启动新Task
  3. standardsingleTop启动新Task,不仅要求新的taskAffinity,而且需要FLAG_ACTIVITY_NEW_TASK
  4. 如果有后台Task和要启动的Activity具有相同的taskAffinity,则不会启动新的Task,而是将后台Task切换到前台,并根据其他属性和标签重新安排后台Task中的Activity和新Activity
  5. taskAffinity的值应该是以‘.’开头的字符串

其他多Task属性和标签

只有standardsingleTop类型的Activity才可能出现多个实例。因此,只有这两类Activity才可能出现多个实例,并处于不同的Task中。下面的讨论,也仅限于这两类。

FLAG_ACTIVITY_NEW_DOCUMENT和documentLaunchMode都是5.0的新特性。通过FLAG_ACTIVITY_NEW_DOCUMENT启动一个新的Task,不需要指定taskAffinity。因此,最好不要将taskAffinity与FLAG_ACTIVITY_NEW_DOCUMENT混用。

在实测中发现,never无法使FLAG_ACTIVITY_NEW_DOCUMENT失效,只是使FLAG_ACTIVITY_MULTIPLE_TASK失效。

Task相关的其他参数

这部分的参数主要处理以下两个问题,演示代码不包括这部分的例子。

其它xml元素

  1. alllowTaskReparenting:默认false,只有standard和singleTop有效,表示Activity实例可以换到其他Task中。(通过应用图标启动程序时会生效,在程序内通过FLAG_ACTIVITY_NEW_TASK切换任务时,不生效)例子:浏览器。
  2. finishOnTaskLaunch:默认false,通过应用图标重新启动程序时,这个Activity会被销毁。
  3. clearTaskOnLaunch:用于Task root,默认false,启动时会清空Task上的其它Activity,只保留root。(通过应用图标启动程序时会生效,通过最近任务启动时不生效)
  4. alwaysRetainTaskState:用于Task root,默认false,在应用切换到后台30分钟后会被系统清理。如果为true则不会被系统清理
  5. noHistory:页面不可见时被自动销毁,不会保存在mHistory

其他Intent.FLAG

  1. FLAG_ACTIVITY_CLEAR_TOP:启动的Activity存在,则不创建新实例,而是使用原有实例,并清空上面的其它Activity。在Activity是singleTask,或者Intent中有FLAG_ACTIVITY_SINGLE_TOP,这个Activity不会重新创建。
  2. FLAG_ACTIVITY_REORDER_TO_FRONT:Activity会重新排序,任何Activity都不会被销毁。
  3. FLAG_ACTIVITY_NO_HISTORY:和xml中的noHistory效果相同
  4. FLAG_ACTIVITY_TASK_ON_HOME:后退时直接回Home,而不会回到之前的Task

Task和Process的关系

之前文章的《怎么处理SaveState》的末尾也提到的Task和Process的关系。这里重复一遍。

我们先看下再ActivityManagerService中进程Process和Task的关系

Task&Process.gif
  1. ActivityManagerService通过一个列表mHistory来管理所有ActivityRecord
  2. 相同TaskRecord中的ActivityRecord在列表中处于连续位置
  3. 同一个TaskRecord中的ActivityRecord可能处于不同的ProcessRecord

由于以下两个因素,使得很难找到Task和进程之间关联的清晰线索。

先看Task中Activity销毁

再看进程被杀

我们以一个简化的例子讨论两者的关系。假设:

Momory Usage Process1 Process2 Process 3
Task1 60M 20M -
Task2 20M 20M -
Task3 - - 40M

如果T1 P1部分消耗的内存由60M上升到75M,由于P1的总内存消耗达到95M,所以会导致P1 T2中的Activity被销毁。

如果T1 P2部分消耗的内存由20M上升到50M,会导致系统总内存消耗达到190M。此时三个Process中,P1和P2和前台Task关联,优先级较高,所以系统会杀掉P3。

这个例子,只是对两者关系的一个简要说明。系统对进程的实际处理方式要复杂得多!

上一篇 下一篇

猜你喜欢

热点阅读