Activity 的 LaunchMode(启动模式)
首先介绍一下 Activity 的默认启动模式:
当我们多次启动同一个 Activity 的时候,系统会创建多个实例并把它们一一放入任务栈中,当我们单击 back
键,会发现这些Activity会一一回退。(任务栈是一种 “先进后出” 的栈结构)每按一下 back 键就会有一个 Activity
出栈,直到栈空为止,当栈中无任何 Activity 的时候,系统就会回收这个任务栈。
当然这样也存在一定的弊端:
当我们多次启动同一个 Activity,系统会重复创建多个实例。
四种LaunchMode
所以 Android 提供了启动模式修改系统的默认行为。目前有四中启动模式:standard、singleTop、singleTask 和 singleInstance:
-
standard:这就是系统默认模。这是一种典型的多实例实现,一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。在这种模式下,谁启动了这个 Activity 那么这个 Activity 就运行在启动它的那个 Activity 所在的栈中。比如 Activity A 启动了 Activity B(B 是标准模式),那么 B 就会进入到 A 所在的栈中。
但是当非 Activity 类型的 Context(如 ApplicationContext)去启动 standard 模式的 Activity 会报错:
这是由于非 Activity 类型的 Context并没有所谓的任务栈,所以出现问题,解决方法是为待启动 Activity 指定FLAG_ACTIVITY_NEW_TASK 标记位,这样启动的时候会为它创建一个新的任务栈,这种时候启动 Activity 实际是以 singleTask 模式启动的。 -
singleTop:栈顶复用模式。如果新 Activity 已经位于任务栈的栈顶,那么此 Activity 不会被重新创建,同时它的 onNewIntent 方法会被回调,通过此方法我们可以取出当前请求的信息。 注意:这个 Activity 的 onCreate、onStart 不会被系统调用,因为它并没有发生改变。如果新 Activity 的实例已存在但不是位于栈顶,那么新 Activity 仍然会重新创建。
-
singleTask:栈内复用模式。这是一种单实例模式,在这种模式下,只要 Activity 在一个栈中存在,那么多次启动此 Activity 都不会重新创建实例,和 singleTop 一样,系统也会回调其 onNewIntent。举例子理解:
-
singleInstance:单实例模式。这是一种加强的 singleTask 模式,它具有 singleTask 的所有特性,还加强了一点,就是就要此模式的 Activity 只能单独地位于一个任务栈中,比如 Activity A 是 singleInstance 模式,当 A 启动后,系统会为它创建一个新的任务栈,然后 A 独自在这个新的任务栈中,由于栈内复用特性,后续请求均不会创建新的 Activity,除非这个独特的任务栈被系统销毁了。
另一个问题,在 singleTask 启动模式中,多次提到某个 Activity 所需的任务栈,什么是 Activity 所需要的任务栈呢?
这要从一个参数说起:TaskAffinity,可以翻译为任务相关性。这个参数标识了一个 Activity 所需要的任务栈的名字,默认情况下,所有 Activity 所需的任务栈为应用的包名。我们可以为每个 Activity 都单独指定 TaskAffinity 属性(不能和包名一样,否则没意义)。
TaskAffinity 属性主要和 singleTask 启动模式或者 allowTaskReparenting 属性配对使用,在其他情况下没有意义:
- 和 singleTask 启动模式
- 和 allowTaskReparenting 属性
如何给 Activity 指定启动模式呢?
- 通过 AndroidMenifest 为 Activity 指定启动模式:
- 通过在 Intent 中设置标志位来为 Activity 指定启动模式:
两者区别:
- 优先级第二种方式高于第一种方式。
- 在限定范围上有所不同,比如第一种方式无法直接为 Activity 设定FLAG_ACTIVITY_CLEAR_TOP 标识,而第二种方式无法为 Activity 指定 singleInstance 模式。
Activity 的 Flags(标记)
介绍一些比较常用的标记位:
- FLAG_ACTIVITY_NEW_TASK
这个标记位的作用是为 Activity 指定 “singleTask” 启动模式,起效果和在 XML 中指定该启动模式相同。 - FLAG_ACTIVITY_SINGLE_TOP
这个标记位的作用是为 Activity 指定 “singleTop” 启动模式,起效果和在 XML 中指定该启动模式相同。 - FLAG_ACTIVITY_CLEAR_TOP
具有此标记位的 Activity,当他启动时,在同一个任务栈中所有位于它上面的 Activity 都要出栈。这个模式一般需要和 FLAG_ACTIVITY_NEW_TASK 配合使用,在这种情况下被启动的 Activity 的实例如果已经存在,那么系统就会调用它的 onNewIntent 方法。如果被启动的 Activity 采用 standard 模式启动,那么它连同它之上的 Activity 都要出栈,系统会重新创建新的 Activity 实例放入栈顶。 - FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
具有这个标记的 Activity 不会出现在历史 Activity 的列表中,当某些情况下我们不希望用户通过历史列表回到我们的 Activity 的时候这个标记位比较有用。它等同于在 XML 中指定 Activity 的属性 android:excludeFromRecents=“true”。