今天继续来任务和返回栈,应用通常包含多个Activity,任务是指在执行特定作业时与用户交互的一系列Activity,这些Activity按照各自的打开顺序排列在堆栈中。
后天可以同时运行多个任务,但是如果用户同时运行多个后台任务,则系统可能会开始销毁后台Activity,以回收内存资源,从而导致Activity状态丢失,故如果要避免用户的信息丢失,应主动通过在Activity中实现onSaveInstanceState()回调方法在保留工作。
定义启动模式:
启动模式允许定义Activity的新实例如何与当前任务关联,可以通过两种方式定义不同的启动模式。
使用清单文件:在清单文件中声明Activity时,可以使用指定的Activity在启动时应该如何与任务关联。
使用Intent标志:调用startActivity()时,可以在Intent中加入一个标志,用于声明新Activity如何与当前的任务关联。
因此,如果 Activity A 启动 Activity B,则 Activity B 可以在其清单文件中定义它应该如何与当前任务关联(如果可能),并且 Activity A 还可以请求 Activity B 应该如何与当前任务关联。如果这两个 Activity 均定义 Activity B 应该如何与任务关联,则 Activity A 的请求(如 Intent 中所定义)优先级要高于 Activity B 的请求(如其清单文件中所定义)。注:某些适用于清单文件的启动模式不可用作 Intent 标志,同样,某些可用作 Intent 标志的启动模式无法在清单文件中定义。
使用清单文件
在清单文件中声明 Activity 时,可以使用<activity>元素的launchMode属性指定 Activity 应该如何与任务关联。
launchMode属性指定有关应如何将 Activity 启动到任务中的指令。可以分配给launchMode属性的启动模式共有四种:
standard, singletTop, singleTask, singleInstance
"standard"(默认模式)
例如,假设任务的返回栈包含根 Activity A 以及 Activity B、C 和位于顶部的 D(堆栈是 A-B-C-D;D 位于顶部)。收到针对 D 类 Activity 的 Intent。如果 D 具有默认的 "standard" 启动模式,则会启动该类的新实例,且堆栈会变成 A-B-C-D-D。但是,如果 D 的启动模式是 "singleTop",则 D 的现有实例会通过 onNewIntent() 接收 Intent,因为它位于堆栈的顶部;而堆栈仍为 A-B-C-D。但是,如果收到针对 B 类 Activity 的 Intent,则会向堆栈添加 B 的新实例,即便其启动模式为 "singleTop" 也是如此。
注:为某个 Activity 创建新实例时,用户可以按“返回”按钮返回到前一个 Activity。 但是,当 Activity 的现有实例处理新 Intent 时,则在新 Intent 到达 onNewIntent() 之前,用户无法按“返回”按钮返回到 Activity 的状态。
注:尽管 Activity 在新任务中启动,但是用户按“返回”按钮仍会返回到前一个 Activity。
使用Intent标志:
启动Activity时,可以通过传递给startActivity()的Intent中加入相应的标志,修改Activity与其任务的默认关联方式。
FLAG_ACTIVITY_NEW_TASK
onNewIntent()
中收到新 Intent。
正如前文所述,这会产生与 "singleTask"
launchMode
值相同的行为。
FLAG_ACTIVITY_SINGLE_TOP
onNewIntent()
的调用,而不是创建 Activity 的新实例。
正如前文所述,这会产生与 "singleTop"
launchMode
值相同的行为。
FLAG_ACTIVITY_CLEAR_TOP
onNewIntent()
将此 Intent 传递给 Activity 已恢复的实例(现在位于顶部),而不是启动该 Activity 的新实例。
产生这种行为的 launchMode
属性没有值。
FLAG_ACTIVITY_CLEAR_TOP
通常与 FLAG_ACTIVITY_NEW_TASK
结合使用。一起使用时,通过这些标志,可以找到其他任务中的现有 Activity,并将其放入可从中响应 Intent 的位置。
注:如果指定 Activity 的启动模式为 "standard"
,则该 Activity 也会从堆栈中移除,并在其位置启动一个新实例,以便处理传入的 Intent。 这是因为当启动模式为 "standard"
时,将始终为新 Intent 创建新实例。
“关联”指示 Activity 优先属于哪个任务。默认情况下,同一应用中的所有 Activity 彼此关联。 因此,默认情况下,同一应用中的所有 Activity 优先位于相同任务中。
可以修改 Activity 的默认关联。 在不同应用中定义的 Activity 可以共享关联,或者可为在同一应用中定义的 Activity 分配不同的任务关联。
可以使用 <activity> 元素的 taskAffinity 属性修改任何给定 Activity 的关联。
taskAffinity 属性取字符串值,该值必须不同于在 <manifest> 元素中声明的默认软件包名称,因为系统使用该名称标识应用的默认任务关联。
在两种情况下,关联会起作用:启动 Activity 的 Intent 包含 FLAG_ACTIVITY_NEW_TASK 标志。
Activity 将其 allowTaskReparenting 属性设置为 "true"。
清理返回栈:
如果用户长时间离开任务,则系统会清除所有 Activity 的任务,根 Activity 除外。 当用户再次返回到任务时,仅恢复根 Activity。系统这样做的原因是,经过很长一段时间后,用户可能已经放弃之前执行的操作,返回到任务是要开始执行新的操作。
可以使用下列几个 Activity 属性修改此行为:
- 如果在任务的根 Activity 中将此属性设置为 "true",则不会发生刚才所述的默认行为。即使在很长一段时间后,任务仍将所有 Activity 保留在其堆栈中。 clearTaskOnLaunch
- 如果在任务的根 Activity 中将此属性设置为 "true",则每当用户离开任务然后返回时,系统都会将堆栈清除到只剩下根 Activity。 换而言之,它与 alwaysRetainTaskState 正好相反。 即使只离开任务片刻时间,用户也始终会返回到任务的初始状态。 finishOnTaskLaunch
- 此属性类似于 clearTaskOnLaunch,但它对单个 Activity 起作用,而非整个任务。 此外,它还有可能会导致任何 Activity 停止,包括根 Activity。 设置为 "true" 时,Activity 仍是任务的一部分,但是仅限于当前会话。如果用户离开然后返回任务,则任务将不复存在。
启动任务
<activity ... >
<intent-filter ... >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
...
</activity>
此类 Intent 过滤器会使 Activity 的图标和标签显示在应用启动器中,让用户能够启动 Activity 并在启动之后随时返回到创建的任务中。