urlname
type
Post
password
SyncToConfluence
category
Android
date
May 30, 2024
slug
01HZ4P93NZHG12ZDYVFP4BVQ1Y
icon
Button
catalog
summary
tags
Android
读书笔记
cover
Status
BusyTime
Status 1
status
Published
在 Android 开发中,Activity 作为四大组件之一,是开发者最常接触和使用的组件。它不仅负责界面的展示,还承担了与用户交互的主要任务。理解 Activity 的启动模式,对于开发高效、稳定的应用至关重要。本文将详细解析 Activity 的启动模式,并结合一些最新的专业知识,为大家提供一个全面的理解。
为什么需要启动模式?
我们知道,在默认情况下,当我们多次启动同一个 Activity 的时候,系统会创建多个实例并把它们一一放入任务栈中。当我们单击 Back 键,会发现这些 Activity 会一一回退。这种“后进先出”的栈结构在一定程度上确实满足了一些简单的需求,但在实际开发中,经常会遇到需要修改系统默认行为的情况。为了更好地满足不同的项目需求,Android 提供了启动模式来灵活地管理 Activity 的实例。
目前有四种启动模式:standard、singleTop、singleTask 和 singleInstance。接下来,我们一一介绍它们的含义和使用场景。
四种启动模式
standard(标准模式)
这是系统的默认模式。每次启动一个 Activity 都会重新创建一个新的实例,不管这个实例是否已经存在。被创建的实例的生命周期符合典型情况下 Activity 的生命周期:
onCreate -> onStart -> onResume。这种模式适合大多数普通场景,比如浏览列表,查看详情等。注意,使用 ApplicationContext 启动标准模式的 Activity 时会报错,因为非 Activity 类型的 Context 没有任务栈。
代码示例
任务栈示例
在这种模式下,每次启动 Activity 都会创建一个新实例。例如:
任务栈中的Activity:
启动新Activity E:
再次启动Activity B:
singleTop(栈顶复用模式)
如果新启动的 Activity 已经位于任务栈的栈顶,则不会重新创建实例,而是调用其
onNewIntent 方法。否则,会重新创建实例。这种模式适用于某些不需要重复创建实例的场景,比如阅读文章时,多次点击同一篇文章。代码示例
任务栈示例
假设任务栈中有以下Activity:
启动Activity B(不是栈顶),则新建实例:
再次启动Activity B(栈顶),调用
onNewIntent():singleTask(栈内复用模式)
这种模式下,Activity 在任务栈中只有一个实例。当 Activity 被启动时,系统会检查该任务栈中是否已有该 Activity 的实例,如果有,则会把该实例移到栈顶,并调用
onNewIntent 方法;否则,会创建一个新的实例。适用于需要确保某个 Activity 只有一个实例的场景,比如应用的主页。代码示例
任务栈示例
假设任务栈中的Activity为:
启动Activity E(singleTask):
启动Activity B(singleTask),则 C、D 和 E 被销毁(clearTop),B 被移到栈顶:
singleInstance(单实例模式)
Activity 独占一个新的任务栈,任何新请求都会重用这个实例。这种模式适用于需要与其他应用共享的 Activity,比如电话拨号界面、闹钟等。
代码示例
任务栈示例
假设任务栈中的活动为:
启动活动 E(singleInstance),创建新的任务栈:
再次启动 E,调用
onNewIntent(),不创建新实例。Task Affinity 和任务栈
Task Affinity 概述
Task Affinity 标识了一个 Activity 所需的任务栈的名字。默认情况下,所有 Activity 所需的任务栈的名字为应用的包名。当然,我们可以为每个 Activity 单独指定 Task Affinity 属性,但这个属性值必须不同于包名,否则相当于没有指定。
Task Affinity 的主要使用场景
Task Affinity 属性主要在以下两种情况下有意义:
- 与 singleTask 启动模式配对使用
- 与 allowTaskReparenting 属性结合使用
任务栈类型
任务栈可以分为前台任务栈和后台任务栈:
- 前台任务栈:当前用户正在与之交互的任务栈。
- 后台任务栈:处于暂停状态的任务栈,用户可以通过切换将其调到前台。
Task Affinity 和 singleTask
当 Task Affinity 和 singleTask 启动模式配对使用时,该模式的 Activity 将运行在名字与 Task Affinity 相同的任务栈中。
为了更好地理解 Task Affinity 和 singleTask 启动模式的作用,我们将通过一个具体的例子来说明。这将涉及多个 Activity 和不同的 Task Affinity 设置,以及 singleTask 启动模式的应用。
假设我们有一个新闻应用(com.example.newsapp),它包含以下三个 Activity:
- MainActivity:应用的主界面,显示新闻列表。
- ArticleActivity:显示新闻文章的详细信息。
- UserProfileActivity:显示用户个人资料。
我们希望:
- MainActivity 在默认的任务栈中运行。
- ArticleActivity 在单独的任务栈中运行,并且是 singleTask 模式。
- UserProfileActivity 可以在主任务栈和文章任务栈之间切换。
XML 配置示例
以下是 AndroidManifest.xml 文件中的相关配置:
行为说明
- MainActivity 在应用的默认任务栈中运行,没有特别的 Task Affinity 设置。
- ArticleActivity 使用 singleTask 启动模式,并且 Task Affinity 设置为
com.example.newsapp.articleTask。这意味着: - 每次启动 ArticleActivity 时,如果有与
com.example.newsapp.articleTask相同任务栈的 Activity 存在,它将重用该任务栈,并清空其上的其他 Activity。
- UserProfileActivity 允许任务重新排列 (
allowTaskReparenting="true") 并具有与 ArticleActivity 相同的 Task Affinity。这意味着: - 如果 UserProfileActivity 从 MainActivity 中启动,它会在主任务栈中运行。
- 当 ArticleActivity 被启动且 UserProfileActivity 也在前台时,UserProfileActivity 将重新排列到 ArticleActivity 所在的任务栈中。
示例代码
在 MainActivity 中启动 ArticleActivity 和 UserProfileActivity:
在 ArticleActivity 中启动 UserProfileActivity:
使用流程示例
- 启动应用,MainActivity 加载在默认任务栈中。
- 从 MainActivity 启动 ArticleActivity,ArticleActivity 在新的任务栈中启动,任务栈的名字为
com.example.newsapp.articleTask。
- 从 ArticleActivity 启动 UserProfileActivity,UserProfileActivity 加载在
com.example.newsapp.articleTask任务栈中。
- 按 Back 键返回,先返回 ArticleActivity,再返回 MainActivity。
- 从 MainActivity 启动 UserProfileActivity,UserProfileActivity 在默认任务栈中启动。
- 从 MainActivity 再次启动 ArticleActivity,ArticleActivity 会重用
com.example.newsapp.articleTask任务栈,并清空其上的其他 Activity,因此 UserProfileActivity 会被移除。
Task Affinity 和 allowTaskReparenting 属性
当 Task Affinity 和 allowTaskReparenting 属性结合使用时,会产生特殊效果:
- 如果应用 A 启动了应用 B 的某个 Activity,并且该 Activity 的 allowTaskReparenting 属性为 true,那么当应用 B 被启动后,此 Activity 会从应用 A 的任务栈转移到应用 B 的任务栈中。
示例说明
假设有两个应用:应用A和应用B。应用A中有一个按钮点击事件,会启动应用B的一个 Activity。这个 Activity 的 Task Affinity 被设置为应用B的任务栈,并且 allowTaskReparenting 属性为 true。
示例场景描述
- 应用A启动应用B的 Activity:用户在应用A中点击按钮,启动应用B中的 ActivityB。
- 应用B启动:当用户启动应用B时,ActivityB 将从应用A的任务栈转移到应用B的任务栈。
示例代码
- 应用A中的代码
在应用A中定义启动应用B的 Activity 的按钮点击事件:
- 应用B中的 ActivityB 的配置
在应用B的 AndroidManifest.xml 文件中配置 ActivityB:
行为分析
- 当用户在应用A中点击按钮时,启动了应用B的 ActivityB,此时 ActivityB 运行在应用A的任务栈中。
- 当用户随后启动应用B时,ActivityB 会自动从应用A的任务栈转移到应用B的任务栈中。
示例详细代码
- 应用A的 MainActivity.java
- 应用B的 AndroidManifest.xml
- 应用B的 ActivityB.java
用户交互流程
- 用户打开应用A,点击按钮启动应用B的 ActivityB。
- ActivityB 现在在应用A的任务栈中。
- 用户启动应用B,ActivityB 自动从应用A的任务栈转移到应用B的任务栈中。
启动标志位
标志位 | 作用说明 |
FLAG_ACTIVITY_NEW_TASK | 启动一个新的任务栈。如果目标 Activity 已存在于另一个任务栈中,则该 Activity 及其上方的所有 Activity 会移到新的任务栈中。 |
FLAG_ACTIVITY_SINGLE_TOP | 如果目标 Activity 已位于任务栈的顶部,则复用该实例,并通过 onNewIntent 方法传递新的 Intent,否则创建新实例。 |
FLAG_ACTIVITY_CLEAR_TOP | 如果目标 Activity 已存在于任务栈中,则弹出其上的所有 Activity,并通过 onNewIntent 方法传递新的 Intent。 |
FLAG_ACTIVITY_NO_HISTORY | 启动的 Activity 不会保存在任务栈中,用户离开该 Activity 后即销毁。 |
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | 使启动的 Activity 不出现在“最近任务”列表中。 |
FLAG_ACTIVITY_CLEAR_TASK | 在启动新 Activity 前,清除其所在任务栈中的所有 Activity,并结合 FLAG_ACTIVITY_NEW_TASK 使用。 |
FLAG_ACTIVITY_REORDER_TO_FRONT | 将已存在任务栈中的目标 Activity 移动到前台,而不重新创建实例。 |
- Author:CoderWdd
- URL:https://www.wuinsights.top//article/01HZ4P93NZHG12ZDYVFP4BVQ1Y
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts