1、官方文档
-
public static final int FLAG_ACTIVITY_CLEAR_TASK
如果在传递给 的意向中设置,则 此标志将导致与 在活动开始之前要清除的活动。即活动 成为原本为空的任务和任何旧活动的新根 都完成了。这只能与 结合使用。Context.startActivity()FLAG_ACTIVITY_NEW_TASK -
public static final int FLAG_ACTIVITY_CLEAR_TASK
如果在传递给 的意向中设置,则 此标志将导致与 在活动开始之前要清除的活动。即活动 成为原本为空的任务和任何旧活动的新根 都完成了。这只能与 结合使用。Context.startActivity()FLAG_ACTIVITY_NEW_TASK -
public static final int FLAG_ACTIVITY_NEW_TASK
如果设置,此活动将成为此活动的新任务的开始 历史堆栈。一个任务(从启动它的活动到 下一个任务活动)定义一个原子组的活动,该组 用户可以移动到。任务可以移动到前台和后台; 特定任务中的所有活动始终保留在 相同的顺序。查看任务和返回 堆栈以获取有关任务的更多信息。
此标志通常由需要的活动使用 呈现“启动器”样式的行为:他们为用户提供一个列表 将可以完成的事情分开,否则会完全运行 独立于启动它们的活动。
使用此标志时,如果任务已在为活动运行 您现在正在启动,则不会启动新活动;相反 当前任务将简单地带到屏幕的前面 它最后所处的状态。查看标志 以禁用此行为。FLAG_ACTIVITY_MULTIPLE_TASK
当调用方请求结果时,不能使用此标志 正在启动的活动。 -
public static final int FLAG_ACTIVITY_REORDER_TO_FRONT
如果在传递给 的意向中设置,则 此标志将导致启动的活动被带到其前面 任务的历史记录堆栈(如果它已在运行)。Context.startActivity()
例如,考虑一个由四个活动组成的任务:A、B、C、D。 如果 D 调用 startActivity() 的 Intent 解析为组件 的活动 B,则 B 将被带到历史堆栈的前面, 结果顺序为:A、C、D、B。 如果也是 指定。FLAG_ACTIVITY_CLEAR_TOP -
public static final int FLAG_ACTIVITY_SINGLE_TOP
如果设置,则在活动已在运行时不会启动该活动 位于历史记录堆栈的顶部。
2、了解任务和返回堆栈——使用清单文件
在清单文件中声明 Activity 时,可以使用 元素的 launchMode 属性指定 Activity 应该如何与任务关联。
launchMode 属性说明了 Activity 应如何启动到任务中。您可以为 launchMode 属性指定 4 种不同的启动模式:
“standard”(默认模式)
默认值。系统在启动该 Activity 的任务中创建 Activity 的新实例,并将 intent 传送给该实例。Activity 可以多次实例化,每个实例可以属于不同的任务,一个任务可以拥有多个实例。
“singleTop”
如果当前任务的顶部已存在 Activity 的实例,则系统会通过调用其 onNewIntent() 方法来将 intent 转送给该实例,而不是创建 Activity 的新实例。Activity 可以多次实例化,每个实例可以属于不同的任务,一个任务可以拥有多个实例(但前提是返回堆栈顶部的 Activity 不是该 Activity 的现有实例)。
例如,假设任务的返回堆栈包含根 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 时,用户将无法通过按返回按钮返回到 onNewIntent() 收到新 intent 之前的 Activity 状态。
“singleTask”
系统会创建新任务,并实例化新任务的根 Activity。但是,如果另外的任务中已存在该 Activity 的实例,则系统会通过调用其 onNewIntent() 方法将 intent 转送到该现有实例,而不是创建新实例。Activity 一次只能有一个实例存在。
注意:虽然 Activity 在新任务中启动,但用户按返回按钮仍会返回到上一个 Activity。
“singleInstance”
与 “singleTask” 相似,唯一不同的是系统不会将任何其他 Activity 启动到包含该实例的任务中。该 Activity 始终是其任务唯一的成员;由该 Activity 启动的任何 Activity 都会在其他的任务中打开。
3、了解任务和返回堆栈——使用 Intent 标记
启动 Activity 时,您可以在传送给 startActivity() 的 intent 中添加相应的标记来修改 Activity 与其任务的默认关联。您可以使用以下标记来修改默认行为:
FLAG_ACTIVITY_NEW_TASK
在新任务中启动 Activity。如果您现在启动的 Activity 已经有任务在运行,则系统会将该任务转到前台并恢复其最后的状态,而 Activity 将在 onNewIntent() 中收到新的 intent。
这与上一节中介绍的 “singleTask” launchMode 值产生的行为相同。
FLAG_ACTIVITY_SINGLE_TOP
如果要启动的 Activity 是当前 Activity(即位于返回堆栈顶部的 Activity),则现有实例会收到对 onNewIntent() 的调用,而不会创建 Activity 的新实例。
这与上一节中介绍的 “singleTop” launchMode 值产生的行为相同。
FLAG_ACTIVITY_CLEAR_TOP
如果要启动的 Activity 已经在当前任务中运行,则不会启动该 Activity 的新实例,而是会销毁位于它之上的所有其他 Activity,并通过 onNewIntent() 将此 intent 传送给它的已恢复实例(现在位于堆栈顶部)。
launchMode 属性没有可产生此行为的值。
FLAG_ACTIVITY_CLEAR_TOP 最常与 FLAG_ACTIVITY_NEW_TASK 结合使用。将这两个标记结合使用,可以查找其他任务中的现有 Activity,并将其置于能够响应 intent 的位置。
注意:如果指定 Activity 的启动模式为 “standard”,系统也会将其从堆栈中移除,并在它的位置启动一个新实例来处理传入的 intent。这是因为当启动模式为 “standard” 时,始终会为新 intent 创建新的实例。
4、了解任务和返回堆栈——处理亲和性
“亲和性”表示 Activity 倾向于属于哪个任务。默认情况下,同一应用中的所有 Activity 彼此具有亲和性。因此,在默认情况下,同一应用中的所有 Activity 都倾向于位于同一任务。不过,您可以修改 Activity 的默认亲和性。在不同应用中定义的 Activity 可以具有相同的亲和性,或者在同一应用中定义的 Activity 也可以被指定不同的任务亲和性。
您可以使用 元素的 taskAffinity 属性修改任何给定 Activity 的亲和性。
taskAffinity 属性采用字符串值,该值必须不同于 元素中声明的默认软件包名称,因为系统使用该名称来标识应用的默认任务亲和性。
亲和性可在两种情况下发挥作用:
当启动 Activity 的 intent 包含 FLAG_ACTIVITY_NEW_TASK 标记时。
默认情况下,新 Activity 会启动到调用 startActivity() 的 Activity 的任务中。它会被推送到调用方 Activity 所在的返回堆栈中。但是,如果传递给 startActivity() 的 intent 包含 FLAG_ACTIVITY_NEW_TASK 标记,则系统会寻找其他任务来容纳新 Activity。通常会是一个新任务,但也可能不是。如果已存在与新 Activity 具有相同亲和性的现有任务,则会将 Activity 启动到该任务中。如果不存在,则会启动一个新任务。
如果此标记导致 Activity 启动一个新任务,而用户按下主屏幕按钮离开该任务,则必须为用户提供某种方式来返回到该任务。有些实体(例如通知管理器)总是在外部任务中启动 Activity,而不在它们自己的任务中启动,因此它们总是将 FLAG_ACTIVITY_NEW_TASK 添加到传递给 startActivity() 的 intent 中。如果您的 Activity 可由外部实体调用,而该实体可能使用此标记,请注意用户可以通过一种独立的方式返回到所启动的任务,例如使用启动器图标(任务的根 Activity 具有一个 CATEGORY_LAUNCHER intent 过滤器;请参阅下面的启动任务部分)。
当 Activity 的 allowTaskReparenting 属性设为 “true” 时。
在这种情况下,一旦和 Activity 有亲和性的任务进入前台运行,Activity 就可从其启动的任务转移到该任务。
举例来说,假设一款旅行应用中定义了一个报告特定城市天气状况的 Activity。该 Activity 与同一应用中的其他 Activity 具有相同的亲和性(默认应用亲和性),并通过此属性支持重新归属。当您的某个 Activity 启动该天气预报 Activity 时,该天气预报 Activity 最初会和您的 Activity 同属于一个任务。不过,当旅行应用的任务进入前台运行时,该天气预报 Activity 就会被重新分配给该任务并显示在其中。
提示:如果一个 APK 文件中包含了就用户角度而言的多个“应用”,您可能需要使用 taskAffinity 属性为每个“应用”所关联的 Activity 指定不同的亲和性。
5、官方说明 android:launchMode
有关 activity 如何启动的说明。共有五种模式可与 Intent 对象中的 activity 标志(FLAG_ACTIVITY_* 常量)协同工作,以确定在调用 activity 处理 intent 时应执行的操作。
“standard”
“singleTop”
“singleTask”
“singleInstance”
“singleInstancePerTask”
默认模式为 “standard”。
如下表所示,这些模式可分为两大类:“standard” 和 “singleTop” activity 是一类,“singleTask”、“singleInstance” 和 “singleInstancePerTask” activity 是另一类。启动模式为 “standard” 或 “singleTop” 的 activity 可以多次实例化。
实例可归属任何任务,并且可位于 activity 任务中的任何位置。通常,它们会启动到名为 startActivity() 的任务中,除非 Intent 对象包含 FLAG_ACTIVITY_NEW_TASK 指令,在这种情况下会选择其他任务。如需了解详情,请参考 taskAffinity 属性。
相比之下,“singleTask”、“singleInstance” 和 “singleInstancePerTask” activity 的行为有所不同。“singleInstancePerTask” 始终位于 activity 任务的根位置。此外,设备一次只能保留一个 “singleInstance” activity 实例,而 "singleInstancePerTask activity 在 FLAG_ACTIVITY_MULTIPLE_TASK 或 FLAG_ACTIVITY_NEW_DOCUMENT 已设置的情况下,在不同的任务中可以多次实例化。
启动模式为 “singleTask” 的 activity 结合了 “singleInstance” 和 “singleInstancePerTask” 的行为:activity 可以多次实例化,并且可以位于具有相同 taskAffinity 的任务中的任意位置。但是,设备只能保留一个用于在 activity 任务的根位置查找 “singleTask” activity 的任务。
“standard” 和 “singleTop” 模式在某一方面有所不同:每当 “standard” activity 有新的 intent 时,系统都会创建类的新实例来响应该 intent。 每个实例处理单个 intent。同样地,您也可以创建新的 “singleTop” activity 实例来处理新的 intent。
不过,如果目标任务的 activity 堆栈顶部已有一个 activity 实例,则该实例会通过调用 onNewIntent() 接收新的 intent。系统不会创建新实例。否则,如果 “singleTop” activity 的一个现有实例在目标任务中,但不在堆栈顶部,或者它位于堆栈顶部,但不在目标任务中,则系统将创建一个新实例并将其推送到堆栈中。
同样地,如果用户向上导航到当前堆栈上的某个 activity,则该行为由父 activity 的启动模式决定。如果父 activity 有启动模式 singleTop(或者 up intent 包含 FLAG_ACTIVITY_CLEAR_TOP),则系统会将该父项置于堆栈顶部,并保留其状态。
导航 intent 由父 activity 的 onNewIntent() 方法接收。如果父 activity 有启动模式 standard(并且 up intent 不包含 FLAG_ACTIVITY_CLEAR_TOP),则系统会将当前 activity 及其父项同时送出堆栈,并创建新的父 activity 实例来接收导航 intent。
“singleInstance” 模式与 “singleTask” 和 “singleInstancePerTask” 也只有一点不同:启动模式为 “singleTask” 或 “singleInstancePerTask” 的 activity 允许其他 activity (必须是 “standard” 和 “singleTop” activity)是其任务的一部分。
另一方面,“singleInstance” activity 不允许其他 activity 成为其任务的一部分。它必须是任务中唯一的 activity。如果它启动另一个 activity,则系统会将该 activity 分配给其他任务,就如同 intent 中包含 FLAG_ACTIVITY_NEW_TASK 一样。
6、官方说明 android:taskAffinity
与 activity 有着相似性的任务。从概念上讲,具有同一相似性的 activity 归属同一任务;从用户的角度来看,则是归属同一“应用”。任务的相似性由其根 activity 的相似性确定。
相似性确定两点内容:activity 更改父项后的任务(请参考 allowTaskReparenting 属性),以及通过 FLAG_ACTIVITY_NEW_TASK 标志启动 activity 时,用于容纳该 activity 的任务。
默认情况下,应用中的所有 activity 都具有同一相似性。您可以设置该属性,以不同方式将其分组,甚至可以在同一任务内放置不同应用中定义的 activity。如要指定 activity 与任何任务均无相似性,请将其设置为空字符串。
如果未设置该属性,则 activity 会继承为应用设置的相似性。请参考 元素的 taskAffinity 属性。应用默认相似性的名称是在 build.gradle 文件中设置的命名空间。
7、其它
Android源码里有较统一的函数命名方式,在AMS中与Activity管理相关很多函数都会带有Locked后缀,表示这些函数的调用都需要多线程同步操作(synchronized),它们会读/写一些多线程共享的数据。
在ActivityStackSupervisor中,还设计了名为ActivityContainer的内部类。 该类是对ActivityStack的封装,相当于开了一个后门,可以通过adb shell am命令对ActivityStack进行读写操作,方便开发和调试。