Activity 的启动模式

Start

1. 概述

1.1 启动过程

Activity 之间的启动流程见下图,从图中可以看出,启动的过程中会受很多因素的影响,导致启动的现象千变万化。

启动流程
1.2 Task

管理并存放 Activity 实例的单元,它是 Activity 的组合,方便用户完成一系列操作。栈结构,符合先进后出特点。Android 系统全局统一管理 Task,Task 不属于任何 App,两个 App 的 Activity 可以放在一个 Task 内。

本文中用这样的框表示一个 Task

本文中用这样的框表示一个 Task。

本文用这样的方块表示 Activity 的对象实例

本文用这样的方块表示 Activity 的对象实例。

Task 在实际压 入Activity 和弹出 Activity

从图中可以看出 Task 在实际压入 Activity 和弹出 Activity 的现象特点。

2. 四大启动模式

2.1 Standard 模式

默认模式,此模式的 Activity 依照顺序压入 Task 中,可以被创建多个对象,不受限制。此模式的使用场景最广泛,大多数普通的 Activity 都使用此模式。

Standard 模式
2.2 SingleTop 模式

SingleTop 模式下的 Activity 的启动效果基本与默认模式相同,但比默认模式多一条限制,当 Task 顶部已有本类的实例时,无法再创建,只能调用已存在实例的 onNewIntent()

SingleTop 模式流程图

下图中的 A2 是 SingleTop 模式的 Activity:

SingleTop 模式

使用场景:避免重复创建。此模式避免连续重复创建 Activity 实例,比如由于点击 Button 跳转慢,用户连续点击而导致的多次创建。

2.3 SingleTask 模式

SingleTask 模式下的 Activity 会主动在系统中寻找属于自己的 Task 及实例,有则复用,无则创建 Task 和实例。复用时会将已存在的实例置顶并销毁阻碍的实例,调用 onNewIntent()

SingleTask 模式流程图

下图中的 A3 是 SingleTask 模式的 Activity:

SingleTask 模式

使用场景:主页面。此模式主要是为了避免系统中存在多个实例,并且避免实例存放到其他 App 的 Task 中,因此很适合主页面。

2.4 SingleInstance 模式

SingleInstance 模式下的 Activity 会主动寻找系统中是否已经存在实例,如果没有则创建一个 Task,并单独存放于其中;否则会复用已存在的实例,并把所在的 Task 移到最前端显示,调用 onNewIntent()

SingleInstance 模式流程图

下图中的 A4 是 SingleInstance 模式的 Activity:

SingleInstance 模式

使用场景:独立功能的页面。此模式适用于程序的独立功能的页面,同时拥有独立的快捷方式,比如一键加速功能。

3. 跨应用启动

3.1 Activity 的启动方式

关于 Activity 的启动方式,我们熟知的有显式启动和隐式启动两种,但身为一个追求知根知底的开发者,不能不去了解其底层含义。

显式启动准确的说是 Component 启动,也就是组件启动,是精准到系统中的某一具体组件的。

隐式启动准确的说是 Action 启动,也就是行为启动,是对要做的行为进行匹配,包含的范围会广一些。

通过下图,我们可以看出,这两种启动的区别在于 Intent 对象的创建方式不同。显式启动是通过创建 ComponentName 对象来创建 Intent 对象,而隐式启动是传递 Action 字符串来创建 Intent 对象。

隐式启动和显式启动区别

在启动其他 App 的 Activity 的具体实现上,我们通常使用的是隐式启动,如下图所示:

隐式启动

其实还可以通过显式启动的方式来启动其他 App 的 Activity,如下图所示:

显式启动
3.2 AppA 启动 AppB 的 Standard 模式 Activity

被启动的 Activity 压入启动者所在的 Task 中,同样可以被创建多个对象,不受限制,现象与同 App 内启动一样。

AppA 启动 AppB 的 Standard 模式 Activity
3.3 AppA 启动 AppB 的 SingleTop 模式 Activity

被启动的 Activity 压入启动者所在的 Task 中,当 Task 顶部已有本类的实例时,无法再创建,只能调用已存在实例的 onNewIntent()。现象与同 App 内启动一样。

AppA 启动 AppB 的 SingleTop 模式 Activity
3.4 AppA 启动 AppB 的 SingleTask 模式 Activity

会优先寻找系统中是否已存在实例,若没有会创建对应的 Task 和实例;如果有会检查其中是否已存在实例,如果没有则创建,否则会 onNewIntent() 复用并置顶,同时销毁阻碍的实例。

AppA 启动 AppB 的 SingleTask 模式 Activity
3.5 AppA 启动 AppB 的 SingleInstance 模式 Activity

会优先寻找系统中是否已存在实例,若没有会创建对应的 Task 和实例,此 Task 只能存放此一个实例;如果有就复用旧实例,将其所在的 Task 移入前台显示。

AppA 启动 AppB 的 SingleInstance 模式 Activity

4.常用 Launch Flag

4.1 Launch Flag 是什么?

Launch Flag 指的是启动 Activity 的 Intent 对象所携带的标记。会对启动的现象产生一定的影响。比如 FLAG_ACTIVITY_SINGLE_TOP、FLAG_ACTIVITY_CLEAR_TOP 等。

4.2 SINGLE_TOP

效果与启动 SingleTop 模式的 Activity 一样。

SINGLE_TOP
4.3 CLEAR_TOP

如果 Task 中已存在实例,清理已存在实例之上的其他实例,同时销毁已存在的实例并重建,走 onCreate()

CLEAR_TOP
4.4 CLEAR_TOP + SINGLE_TOP

如果 Task 中已存在实例,清理已存在实例之上的其他实例,复用已存在的实例,走 onNewIntent()

CLEAR_TOP + SINGLE_TOP
4.5 CLEAR_TOP + SINGLE_TOP + NEW_TASK

如果 Task 中已存在实例,清理已存在实例之上的其他实例,复用已存在的实例,走 onNewIntent()。并且可以在其他 Task 中实现。

适用场景:点击 Notification 的跳转:

CLEAR_TOP + SINGLE_TOP + NEW_TASK
4.6 CLEAR_TASK

销毁被启动的 Activity 所对应的 Task 内的所有 Activity 实例,新建被启动 Activity 实例,放在 Task 的底部。

适用场景:切换用户登录账号

CLEAR_TASK

注意:启动 Standard 和 SingleTop 时,CLEAR_TASK 单独使用无效,必须与 NEW_TASK 一同使用;启动 SingleTask 和 SingleInstance 时,CLEAR_TASK 单独使用有效。

7. EXCLUDE_FROM_RECENTS

当新建 Activity 并且存放在新的 Task 中的根部时,被启动的 Activity 从 RecentApp 列表中消失。

EXCLUDE_FROM_RECENTS

注意:部分手机需要先按 Home 键回到桌面,然后按 RecentApp 键,才能有效。

8. NO_HISTORY

带着这条 Flag 启动的 Activity,一旦 onStop,Activity 就会被销毁。按 Home 键就会销毁。不会留在 Recent 列表中。

适用场景:敏感信息的页面。比如输入密码的页面。

9. REORDER_TO_FRONT

将 Task 中已存在的实例,置顶,不影响其他实例。

若 Task 中已存在实例并且在顶部,那么 Task 顺序保持不变,复用旧实例,回调 onNewIntent()

若 Task 中已存在实例并且不在顶部,会将其移到 Task 顶部,其余 Activity 被向下压一层,回调 onNewIntent()

REORDER_TO_FRONT
10. TASK_ON_HOME

如果被启动的 Activity 的实例存放到了另一个 Task 中,那么按 Back 键回退的时候,当第一个 Task 中的 Activity 回退完之后,会回到桌面,而不会回到启动页面的 Task。

适用场景:使用 Activity 覆盖其他 App 的情形。

TASK_ON_HOME

5. TaskAffinity

5.1 TaskAffinity 概述

TaskAffinity 描述了 Activity 和 Task 之间的亲和性。Activity 和 Task 都有此属性,如果属性值一样,则表示他们亲和性一致。亲和性一致的 Activity 天然应该放在同一个亲和性一致的 Task 里。

此属性的值在 AndroidManifest.xml 文件中配置。

例如:android:taskAffinity=“:string”。如果不配置,默认是以 App 包名为值。

注意:SingleInstance 的 Activity 虽然单独在一个 Task 中,其 TaskAffinity 默认也是包名。

本文中用下图中不同的颜色表示不同 TaskAffinity 值的 Task 和 Activity。

TaskAffinity 值的 Task 和 Activity
5.2 同/异 App 启动不同 TaskAffinity 的 Activity

Activity 的启动,在本质上和它所属的 App 无关,只与它的 TaskAffinity 值相关。因此,上述两种情况效果一致。

注意:启动 Standard 和 SingleTop 的 Activity 时,需要携带 NEW_TASK,才能让不同 TaskAffinity 的 Activity 新建 Task。

下图中的 B1 是 Standard 模式的 Activity,B2 是 SingleTop 模式的 Activity:

下图中的 B3 是 SingleTask 模式的 Activity,B4 是 SingleInstance 模式的 Activity:

5.3 启动不同 App 但是配置了相同 TaskAffinity 值的 Activity

只要 TaskAffinity 的值一样,就会天然归属在同一个 Task 中,不管是不是一个 App。

某项目出现了点击自己的 ICON 结果弹出其他 App 的页面,正是因为 TaskAffinity 值一样。

下图中 AppA 的 A2 和 AppB 的 B2 拥有相同的 TaskAffinity 值 z,和两个 App 的默认的 TaskAffinity 值都不一样。

参考文献
[1]《Android系统源代码情境分析》罗升阳

申明:开始的图片来源网络,侵删

你可能感兴趣的:(Activity 的启动模式)