Android Activity 启动模式和任务栈

在掌握 Activity 基本生命周期后,我们能完成单个 Activity 内的业务逻辑,但这不足以支撑优质的 APP 体验。Android 系统通过任务栈(Task Stack) 管理整个 APP 的 Activity 实例,合理调度任务栈是提升用户体验的关键。任务栈遵循先进后出(FILO) 的线性表结构:新启动的 Activity 会被压入栈顶并处于活动状态,其他 Activity 虽退出活动状态(触发 onStop()),但只要未触发 onDestroy(),就会保留在栈中。

默认情况下,点击返回键或调用 finish() 方法会移除栈顶 Activity,让栈内下一个 Activity 恢复活动状态。但通过 AndroidManifest.xmlandroid:launchMode 属性,或 Intent 携带的 Flag,可打破这一默认行为。

一、AndroidManifest 声明的启动模式

1. standard(标准模式)

standard 是所有 Activity 的默认启动模式,未显式指定时均采用此模式。该模式下,每次启动 Activity 都会创建全新的实例,新实例会被压入当前任务栈的栈顶,覆盖原有栈顶 Activity。

任务栈状态示意图

# 初始状态:栈内有 Activity A(栈底)
|        |
|   A    |  <-- 栈底
|________|

# 启动 Activity B(standard 模式)
|        |
|   B    |  <-- 栈顶(新实例)
|   A    |
|________|

# 再次启动 Activity B(standard 模式)
|        |
|   B₂   |  <-- 栈顶(全新 B 实例)
|   B₁   |
|   A    |
|________|

2. singleTop(栈顶复用模式)

指定为 singleTop 模式的 Activity,启动时系统会先检查当前栈顶是否是该 Activity 实例:

  • 若栈顶已是目标 Activity,不会创建新实例,而是复用栈顶实例并调用其 onNewIntent() 方法;
  • 若栈顶不是目标 Activity,则创建新实例并压入栈顶。

该模式适用于接收消息后展示的界面(如通知栏点击打开的详情页),避免重复创建相同的栈顶页面。

任务栈状态示意图

# 初始状态:栈内有 A、B、C(C 为 singleTop 模式,栈顶)
|        |
|   C    |  <-- 栈顶(singleTop)
|   B    |
|   A    |
|________|

# 再次启动 Activity C
|        |
|   C    |  <-- 复用原实例,调用 onNewIntent()
|   B    |
|   A    |
|________|

# 启动 Activity D 后,再启动 Activity C
|        |
|   C₂   |  <-- 栈顶(新实例,因原 C 不在栈顶)
|   D    |
|   C₁   |
|   B    |
|   A    |
|________|

3. singleTask(栈内复用模式)

singleTask 是比 singleTop 范围更广的复用模式:启动时系统会检查整个任务栈是否存在目标 Activity 实例:

  • 若存在:将该实例移动到栈顶,并销毁其上方所有 Activity;
  • 若不存在:创建新实例并压入栈顶。

注意:

  1. 同一 APP 内启动 singleTask Activity 时,仅在当前任务栈内检查/复用;
  2. 其他程序启动该 Activity 时,会为其创建新任务栈;
  3. singleTask Activity 已存在于后台任务栈,启动后该后台任务栈会整体切换到前台。

任务栈状态示意图

# 初始状态:当前任务栈有 A、B、C、D(C 为 singleTask 模式)
|        |
|   D    |  <-- 栈顶
|   C    |
|   B    |
|   A    |
|________|

# 启动 Activity C(singleTask 模式)
|        |
|   C    |  <-- 栈顶(移动上来)
|   B    |
|   A    |
|________|
# D 被销毁(onDestroy() 触发)

# 跨 APP 启动 singleTask 的 Activity C(无现有实例)
# 新任务栈创建:
任务栈1(原APP):| A | B |
任务栈2(新):  | C |  <-- 独立栈,仅含 C

4. singleInstance(单实例模式)

singleInstance 是最特殊的启动模式:

  • 声明为此模式的 Activity 会被放入全新的独立任务栈,且该任务栈中仅存在这一个 Activity
  • 该 Activity 实例全局共享,再次启动时不会创建新实例,直接调出该任务栈并将 Activity 置于前台。

任务栈状态示意图

# 启动 singleInstance 的 Activity X
任务栈1(原APP):| A | B |
任务栈2(独立):| X |  <-- 仅含 X,全局唯一

# 从原 APP 再次启动 Activity X
任务栈1(原APP):| A | B |
任务栈2(独立):| X |  <-- 复用实例,切换到前台

重要注意事项

若在 singleTopsingleInstance 模式的 Activity A 中,通过 startActivityForResult() 启动 Activity B,系统会直接返回 Activity.RESULT_CANCELED,不会等待 B 的返回结果。
原因是 Framework 层限制:不同 Task 间默认不支持数据回传,若需传递数据,需通过 Intent 显式传递。

二、其他补充说明

  1. 除了在 AndroidManifest.xml 中声明启动模式,也可通过 Intent 设置 Flag(如 FLAG_ACTIVITY_SINGLE_TOPFLAG_ACTIVITY_NEW_TASK 等),指定单次启动的模式;
  2. AndroidManifest.xml 还提供了清理任务栈的标签(如 android:clearTaskOnLaunchandroid:finishOnTaskLaunch 等),可参考官方 API 文档了解用法;
  3. 任务栈的调度需结合项目实际需求,禁止滥用——错误的启动模式会导致页面跳转逻辑混乱、内存泄漏或用户操作不符合预期。

总结

  1. 任务栈核心规则是“先进后出”,launchMode 可打破默认的实例创建/栈管理逻辑;
  2. standard 每次新建实例,singleTop 复用栈顶,singleTask 复用栈内实例并清理上方页面,singleInstance 独占任务栈且全局唯一;
  3. singleTop/singleInstance 不支持 startActivityForResult() 回传结果,需通过 Intent 传递数据。
posted @ 2016-08-18 19:02  灰色飘零  阅读(1002)  评论(0)    收藏  举报