启动模式与 flag

529 阅读4分钟

一些说明

为描述方便,被启动的 Activity 称为被启者,启动的 Activity 称为启动者。

  1. taskAffinity 并不是区分 task 的标识,两个 task 可以有相同的 taskAffinity
  2. 启动模式与 Flag 冲突时,以 flag 为准
  3. 启动模式与 flag 的作用无非就是两个:寻找 activity 要寄存的 task 以及找到 task 后怎么处理 task 中的数据
  4. 对 task 中数据的处理也无法是两种:删除目标之上的所有 activity 或者 清空整个 task
  5. 以下均不说明 onNewIntent 是否被调用,这应该是常识

不添加 flag

有 singleInstance

  1. 无论被启动者还是启动者:模式为 singleInstalce 者独占一 Task,task 的 taskAffinity 如果没设置就是包名
  2. 启动者为 singleInstance,被启动者按 taskAffinity 寻找 task,没有就新建,会忽略被启动者的启动模式。原理就是 AMS 在处理启动模式时,如果启动者有 singleInstance,会为 Intent 添加到 FLAG_ACTIVITY_NEW_TASK 标志

有 singleTask

  1. 被启动者有:按 taskAffinity(没有指定就是包名) 寻找 task,没有找到就新建,如果找到了就会清空被启动者之上的所有 activity
  2. 启动者有:在排除上面各种情况下,与普通启动默认一样,被启动者会进入到启动者所在的 task 中

标准与 singleTop

  1. 排除上面的各种情况后,taskAffinity 会被忽略,即使设置过
  2. 启动情况就是网上所说:前者永远新建,后者被启动者在 task 顶部时不会新建、其余时候均新建

NEW_TASK

不要被 new_task 名字所误导,它并不是一定会新建 task,它的作用是 按 taskAffinity(没有指定就是包名) 寻找 task,如果有就使用没有就新建;找到后是否会清空被启动者之上的 activity 就看被启动者的启动模式

看 AMS 源码的话,singleInstance 与 singleTask 也是为 intent 添加到 new_task 标识

有几种情况:

  1. A\B\C 标准启动、均不指定 taskAffinity,A 启动 B,B 启动 C,C 启动 B 时设置过 FLAG_ACTIVITY_NEW_TASK,那么 task 中就有个 activity

  2. A\C 标准启动、B 是 singleTop、均不指定 taskAffinity,则结果同上

  3. A\C 标准启动、B 是 singleTask、均不指定 taskAffinity,A 启动 B,B 启动 C,C 启动 B 时设置 FLAG_ACTIVITY_NEW_TASK,那么 task 中就有个 activity:A 以及 A 启动的 B

情况 3 和情况 1/2 的区别在于:singleTask 有清空上面 activity 的作用

CLEAR_TOP

与 FLAG_ACTIVITY_NEW_TASK 结合使用。

上面说过 new_task 只是根据 taskAffinity 寻找对应的 task,清不清空目标之上的元素依赖于目标的启动模式,加上 clear_top 就不一样了:强制清空被启动者之上的 activity,无论被启动者的启动模式是什么

  1. 若被启动者启动模式是标准,则连被启动者也清掉,然后新建被启动者
  2. 否则,不新建被启动者,但回调其 onNewIntent

SINGLE_TOP

  1. 优先级高于 FLAG_ACTIVITY_NEW_TASK。比如 A,标准启动,但设置了 taskAffinity。如果 A.startActivity(A) 时设置了 new_task,那么参数 A 会寄存到 taskAffinity 指定的 task 中。但如果同时设置 single_top,那会执行调用 A 的 onNewIntent,不会产生新 A
  2. 被启动者是 task 顶部元素时,不会新建,但会执行 onNewIntent,否则会新建

情形一:A 标准启动,但有 taskAffinity,B singleInstance。B 启动 A 时设置 single_top,则 A 会在 taskAffinity 对应的 task 中。这主要是 singleInstance 的作用

CLEAR_TASK

无论被启动者的启动模式,该 flag 都会:清空旧 task,同时创建一个新被启动者加入 task 中

  1. 必须与 new_task 一起使用
  2. 若被启动者启动模式为标准或 singleTop,则清空 task,并新建一个被启动者放入 task 中,不执行 onNewIntent
    • 无论被启动者是不是在 task 顶部
  3. 若被启动者启动模式为 singleTask/singleInstance,则清空 task,并新建一个被启动者放入 task 中,并且回调旧 activity 的 onNewIntent,再调用新 Activity#onCreate。不懂这里面的处理逻辑,但看现象是这样的

NO_USER_ACTION

当前的 Intent 是不是由用户操作引起的。主要影响 Activity#onUserLeaveHint 的调用:Intent 中设置了就不会调用,没设置就会调用