Android启动模式以及任务栈分配与区分

6 阅读1分钟

一、启动模式

  1. standard(普通模式)
  2. singleTop(栈顶复用)
  3. singleTask(栈内复用、栈内唯一)
  4. singleInstance(独占新栈)

二、任务栈分配

普通情况下,没有设置 taskAffinity 属性的情况下

singleInstance独占一个栈,其他的都是共用一个栈

APP中指定ActivityB 的Affinity ,ActivityB 的栈会是什么情况的

它的栈分布情况完全取决于你同时使用的“启动模式”(launchMode)taskAffinity 只是告诉系统:“如果需要新建任务栈,或者寻找复用栈时,请优先考虑这个名字(Affinity)对应的栈

情况一:ActivityB 是 standard 或 singleTop (默认情况)

结论:通常仍在主栈中,taskAffinity 几乎不起作用。

  • 行为
    • 当你在主应用(Task A)中启动 ActivityB 时,即使 ActivityB 配置了不同的 taskAffinity,只要启动模式是 standardsingleTop,系统默认还是会把它放入**当前调用者所在的任务栈(Task A)**中。
    • 原因:这两种模式的设计初衷就是跟随调用者。
  • 例外(任务重父级 reparenting)
    • 如果 ActivityB 已经在另一个具有匹配 Affinity 的栈中存在,且应用配置了 allowTaskReparenting="true",那么当应用回到前台时,ActivityB 可能会从当前栈“跳”回它 affinity 对应的那个栈。但这属于特殊情况。
  • 栈分布
    • Task A: [MainActivity, ..., ActivityB] (混合在一起)

情况二:ActivityB 是 singleTask (最常见用法)

结论:会进入一个独立的、以该 Affinity 命名的任务栈。

这是 taskAffinity + singleTask 的经典组合,常用于将特定功能模块隔离。

  • 行为
    1. 系统检查是否存在一个 taskAffinity 等于 ActivityB 所指定值的任务栈。
    2. 如果不存在:系统创建一个全新的任务栈(Task B),并将 ActivityB 作为根 Activity 放入其中。
    3. 如果存在:系统将该栈拉到前台,并复用 ActivityB 实例(清除其上方的 Activity)。
  • 栈分布
    • Task A (主栈): [MainActivity, ...]
    • Task B (独立栈): [ActivityB] (或者 [ActivityB, SubPage],如果在 B 里启动了其他 standard 页面且没改 affinity)
  • 特点
    • ActivityB 拥有了自己的“地盘”。
    • ActivityB 启动其他 standard Activity 时,这些新页面默认会进入 Task B(因为它们继承了 ActivityB 的 affinity),而不是回到 Task A。这可以实现整个功能模块的独立栈管理。

情况三:ActivityB 是 singleInstance

结论:必然进入一个独立的、独占的任务栈。

  • 行为
    • singleInstance 强制要求独占栈。
    • 指定的 taskAffinity 决定了这个独立栈的“逻辑名称”。
    • 如果系统中已有相同 Affinity 的 singleInstance 栈,则复用;否则新建。
  • 栈分布
    • Task A: [MainActivity, ...]
    • Task B: [ActivityB] (绝对独占,不能有其他 Activity)
  • 注意:对于 singleInstance,即使不指定 taskAffinity(使用默认包名),它也会因为模式特性而强制新建栈。指定 Affinity 主要是为了在多应用共享或特定场景下标识这个栈。

问题:

  • 后续启动新的ActivityActivityBsingleInstance 模式并处于其独立的独占栈(假设为 Task B)中时,如果在 ActivityB 内部代码启动了一个新的 standard 模式的 Activity(假设为 ActivityC):

    结论:
    ActivityC 绝对不会 进入 ActivityB 所在的 Task B
    它会被放入 调用者(ActivityB)原本所属的那个任务栈(通常是启动 ActivityB 的那个主栈,假设为 Task A),或者是一个与 ActivityCtaskAffinity 匹配的现有栈

核心总结表

ActivityB 配置

启动模式 (Launch Mode)

栈分布结果

解释

指定了 Affinity

standard / singleTop

通常在原栈

Affinity 被忽略,跟随调用者栈。除非发生任务重父级。

指定了 Affinity

singleTask

新建独立栈 (推荐)

系统会查找或创建一个与该 Affinity 匹配的新栈,B 成为栈底。

指定了 Affinity

singleInstance

新建独立栈 (独占)

强制新建独占栈,Affinity 作为该栈的标识。

问题:

由于 ActivityB 和 ActivityC 不在同一个栈,传统的 startActivityForResult (或新的 ActivityResultLauncher) 在这种跨栈场景下行为可能不符合预期,或者根本无法接收到结果,因为上下文(Context)所属的任务栈发生了切换,如何解决这个问题

使用全局事件总线(EventBus / LiveData / Flow)