做 Android 的同学想必对 activity 启动模式都不陌生,activity 有四种启动模式( standardsingleTopsingleTasksingleInstance),网上和一些书上也有各种讲解,但这些文章大多是针对四种启动模式进行介绍,总是在看过一段时间后就忘掉了。本文希望带你重新理解 activity 启动模式,并理解一些其他的相关概念,而不是仅仅针对四种启动模式。

1. 从 Task 说起

Activity 启动模式是与 task 密切相关的,所以我们先从 task 说起。

A task is a collection of activities that users interact with when performing a certain job. The activities are arranged in a stack (the back stack), in the order in which each activity is opened.

上面这句话是官方文档里的,解释了 Android 中 task 的概念,task 就是若干 activity 组成的一个集合,以栈的形式来管理。在 Android 中,每个 activity 都是运行在 task 中的,前台 task 的栈顶 activity 位于前台,可以直接与用户交互。

那么一个 activity 运行在哪个 task 中是由谁来决定的呢?我们首先来看 taskAffinity,taskAffinity 是影响 Activity 运行在哪个 task 中的第一个因素。

一个 activity 的 taskAffinity 是我们在 manifests.xml 里定义的,每个 Activity 都可以设置一个 android:taskAffinity 属性,它的值是一个字符串。application 元素也有这个属性,它的默认值是 manifest 元素中指定的包名(package 属性)。对于 Activity 的这个属性,当我们不显式设置的时候它就会从 application 元素继承。

那么在 taskAffinity 属性起作用的情况下,除了 taskAffinity 值为空字符串的 Activity,具有相同 taskAffinity 的 Activity 会运行在同一个 task 中,即使它们处于不同的应用中。taskAffinity 为空字符串表示这个 Activity 不会与其他任何 task 关联。

2. manifests.xml 中的 launchMode

我们可以在 manifests.xml 中为 activity 指定 android:launchMode 属性,可以的取值有 standardsingleTopsingleTasksingleInstance,默认值是 standard

那么我们不设置 Intent flags(下文会讲到)的情况下启动一个 activity 的时候,系统就会根据 manifests.xml 里设置的 launchMode 来决定 activity 启动模式。下面是四种启动模式的处理说明。

  • standardsingleTop:在当前 task 中启动,忽略 taskAffinity 属性
    两种模式的区别是 standard 模式每次启动都会创建新的实例,而 singleTop 模式则是若已经有该 activity 的实例存在于 task 栈顶的情况下不再创建新实例,而是回调该实例的 onNewIntent() 方法。

  • singleTask:这时该 activity 要在哪个 task 中运行就由我们前面指定的 taskAffinity 来决定了(该 activity 只能运行在 taskAffinity 与自己的 taskAffinity 相同的 task 中)。并且在这个 task 中该 activity 的实例只允许存在一个,若已经有一个实例在栈顶,就会回调它的 onNewIntent() 方法;若有实例且不在栈顶,系统则会将该 task 中该位于该实例之上的 activity 出栈销毁,使该实例回到前台,并回调其 onNewIntent() 方法。

  • singleInstance:与 singleTask 类似,区别在于 singleInstance 的 task 中只能有一个 activity 实例存在,即该 activity 只能单独运行于一个 task 中。

3. Intent flag

影响 activity 启动模式的另一个地方就是 Intent flag 了。我们可以在使用 Intent 启动一个 activity 的时候可以调用 Intent 的 setFlag() 方法来为它设置标志位,且 Intent flag 具有更高的优先级。影响 activity 启动模式的 Intent flag 有下面几个。

  • FLAG_ACTIVITY_NEW_TASK:在新 task 中启动 activity,效果与 singleTask 模式类似,但不会清除目标 activity 之上的 activity。使用这个 flag 可以实现应用间切换的效果。

  • FLAG_ACTIVITY_SINGLE_TOP:与 singleTop 模式效果相同。

  • FLAG_ACTIVITY_CLEAR_TOP:若目标 activity 在其 task 中已经有实例存在,则将 task 中其上的 activity 出栈销毁,使该实例回到前台,并回调其 onNewIntent() 方法。与 FLAG_ACTIVITY_NEW_TASK 结合使用可以实现 singleTask 模式的效果。