taskAffinity、launchMode 与 flag

1、官方文档

  1. public static final int FLAG_ACTIVITY_CLEAR_TASK
    If set in an Intent passed to , this flag will cause any existing task that would be associated with the activity to be cleared before the activity is started. That is, the activity becomes the new root of an otherwise empty task, and any old activities are finished. This can only be used in conjunction with .Context.startActivity()FLAG_ACTIVITY_NEW_TASK

  2. public static final int FLAG_ACTIVITY_CLEAR_TOP
    If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
    For example, consider a task consisting of the activities: A, B, C, D. If D calls startActivity() with an Intent that resolves to the component of activity B, then C and D will be finished and B receive the given Intent, resulting in the stack now being: A, B.
    The currently running instance of activity B in the above example will either receive the new intent you are starting here in its onNewIntent() method, or be itself finished and restarted with the new intent. If it has declared its launch mode to be “multiple” (the default) and you have not set in the same intent, then it will be finished and re-created; for all other launch modes or if is set then this Intent will be delivered to the current instance’s onNewIntent(). FLAG_ACTIVITY_SINGLE_TOPFLAG_ACTIVITY_SINGLE_TOP
    This launch mode can also be used to good effect in conjunction with : if used to start the root activity of a task, it will bring any currently running instance of that task to the foreground, and then clear it to its root state. This is especially useful, for example, when launching an activity from the notification manager. FLAG_ACTIVITY_NEW_TASK

  3. public static final int FLAG_ACTIVITY_NEW_TASK
    If set, this activity will become the start of a new task on this history stack. A task (from the activity that started it to the next task activity) defines an atomic group of activities that the user can move to. Tasks can be moved to the foreground and background; all of the activities inside of a particular task always remain in the same order. See Tasks and Back Stack for more information about tasks.
    This flag is generally used by activities that want to present a “launcher” style behavior: they give the user a list of separate things that can be done, which otherwise run completely independently of the activity launching them.
    When using this flag, if a task is already running for the activity you are now starting, then a new activity will not be started; instead, the current task will simply be brought to the front of the screen with the state it was last in. See for a flag to disable this behavior. FLAG_ACTIVITY_MULTIPLE_TASK
    This flag can not be used when the caller is requesting a result from the activity being launched.

  4. public static final int FLAG_ACTIVITY_REORDER_TO_FRONT
    If set in an Intent passed to Context.startActivity(), this flag will cause the launched activity to be brought to the front of its task’s history stack if it is already running.
    For example, consider a task consisting of four activities: A, B, C, D. If D calls startActivity() with an Intent that resolves to the component of activity B, then B will be brought to the front of the history stack, with this resulting order: A, C, D, B. This flag will be ignored if FLAG_ACTIVITY_CLEAR_TOP is also specified.

  5. public static final int FLAG_ACTIVITY_SINGLE_TOP
    If set, the activity will not be launched if it is already running at the top of the history stack.

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 一样。
https://developer.android.com/guide/topics/manifest/activity-element?hl=zh-cn

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进行读写操作,方便开发和调试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值