任务与返回栈
本教程共 100 篇 · 第 27 篇 · 更新于 2026-07-28 · 约 9 分钟阅读
27. 任务与返回栈
本节目标:理解任务(Task)和返回栈(Back Stack)是什么、四种启动模式各自的行为和适用场景,会根据需求选启动模式。
任务和返回栈是什么
任务(Task) 是用户完成某件事时交互的一组 Activity 集合。这些 Activity 按打开顺序排成返回栈(Back Stack)。
生活化比喻:任务像一摞扑克牌,每打开一个 Activity 就往牌堆顶上加一张,按返回键就抽走最上面那张。后进先出(LIFO)。
栈顶: Activity C(当前显示)
Activity B
Activity A(根 Activity,最先启动)
栈底
典型流程:
- 桌面点应用图标 -> 系统创建任务,主 Activity A 入栈。
- A 启动 B -> B 入栈顶,A 停止(界面保留)。
- B 启动 C -> C 入栈顶。
- 按返回 -> C 出栈销毁,B 恢复。
- 继续返回 -> B 出栈,A 恢复。
- 再返回 -> A 出栈,任务消失,回到桌面。
任务的生命周期
任务作为一个整体移动:
- 按 Home 键:整个任务进后台(所有 Activity 停止),返回栈保留。
- 从最近任务列表切回:任务回前台,栈顶 Activity 恢复,状态保留。
- 启动新应用:原任务进后台,新应用起一个新任务。
所以用户切来切去时,每个应用的任务栈是独立保留的,能接着用。
Note
- 任务里的 Activity 可能来自不同应用。比如你的应用调起相机 Activity 拍照,相机 Activity 进了你的任务栈。这叫「无缝协作」。
启动模式
默认情况下,每次 startActivity 都会创建新的 Activity 实例入栈。但有些场景你不想创建新实例—比如设置页已经打开了,再点设置应该回到原来的而不是开两个。
启动模式(launchMode)控制 Activity 实例怎么创建和入栈。有四种,在 Manifest 声明:
1. standard(默认)
每次启动都创建新实例,压入调用方的任务栈。
<activity android:name=".StandardActivity" />
<!-- 等价于 android:launchMode="standard" -->
适用:大部分场景。每次都是新界面。
2. singleTop
如果栈顶已经是该 Activity 实例,不创建新的,而是调它的 onNewIntent。否则创建新实例。
<activity android:name=".SingleTopActivity" android:launchMode="singleTop" />
当前栈: [A, B, C]
启动 C -> C 在栈顶,不新建,调 C.onNewIntent()
栈不变: [A, B, C]
启动 B -> B 不在栈顶,创建新 B
栈变成: [A, B, C, B']
适用:
- 通知点击打开的 Activity(避免开一堆)。
- 搜索页、设置页(已在前台时复用)。
Tip
- singleTop 是最常用的非默认模式。适合「这个界面已经在最上面就别再开一个」的场景。
3. singleTask
整个系统里这个 Activity 只有一个实例。它所在的任务栈里,它之上不能有其他 Activity。
当前栈: [A, B, C]
启动 B(singleTask)
结果: B 之上的 C 被销毁,栈变成 [A, B],调 B.onNewIntent()
如果该 Activity 之前在别的任务栈里,系统会切到那个任务栈,把它上面的 Activity 清掉。
<activity android:name=".SingleTaskActivity" android:launchMode="singleTask" />
适用:
- 应用主入口(如邮箱收件箱),保证回到唯一实例。
- 想清掉之上所有界面的场景(如登录成功回到主页)。
4. singleInstance
跟 singleTask 类似,但这个 Activity 独占一个任务,整个系统只有一个实例,且它所在任务里只有它自己。
应用任务栈: [A, B]
启动 C(singleInstance)-> 系统新建任务 [C],C 独占
从 C 启动 D -> D 进应用原任务栈 [A, B, D],C 那个任务还是只有 C
<activity android:name=".SingleInstanceActivity" android:launchMode="singleInstance" />
Warning
- singleInstance 很少用,行为复杂,容易导致导航混乱。除非有强需求(如全局拨号界面),别用。
用 Intent flags 临时控制
除了在 Manifest 声明启动模式,还能用 Intent 的 flag 临时改变行为:
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
}
startActivity(intent)
常用 flags:
| Flag | 作用 |
|---|---|
FLAG_ACTIVITY_NEW_TASK | 在新任务里启动 |
FLAG_ACTIVITY_CLEAR_TOP | 如果目标已在栈里,清掉它上面的 Activity |
FLAG_ACTIVITY_SINGLE_TOP | 等同 singleTop |
FLAG_ACTIVITY_NO_HISTORY | 这个 Activity 不留在栈里,离开即销毁 |
FLAG_ACTIVITY_CLEAR_TASK | 启动时清空目标任务 |
经典场景:通知点击回到主页并清空栈:
val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
taskAffinity:任务亲和性
taskAffinity 定义 Activity 「属于」哪个任务。默认是应用的包名。
<activity
android:name=".SpecialActivity"
android:taskAffinity="com.example.app.special" />
配合 FLAG_ACTIVITY_NEW_TASK 能让 Activity 启动到指定任务。日常很少改,知道有这个属性即可。
Compose 与返回栈
Compose 单 Activity 架构里,返回栈由 Navigation 组件管理,不是 Activity 任务栈:
NavHost(navController, startDestination = "home") {
composable("home") { HomeScreen() }
composable("detail") { DetailScreen() }
composable("settings") { SettingsScreen() }
}
按返回键,Navigation 自动 popBackStack(),回到上一个 Composable。系统返回键集成由 BackHandler 处理:
@Composable
fun DetailScreen() {
BackHandler {
// 拦截返回键,做自定义逻辑
showConfirmDialog()
}
}
Note
- Compose + Navigation 把「Activity 返回栈」简化成「Composable 导航栈」。日常不用操心 launchMode,除非涉及外部 Activity 调用。
常见场景与选择
| 场景 | 推荐方案 |
|---|---|
| 普通页面跳转 | standard(默认) |
| 通知点击打开主页 | singleTop + FLAG_ACTIVITY_CLEAR_TOP |
| 登录成功回主页清栈 | Intent flags: NEW_TASK + CLEAR_TASK |
| 全局唯一设置页 | singleTask |
| 系统拨号、相机入口 | singleInstance(少用) |
| Compose 内部页面切换 | Navigation 组件,不用 Activity |
小结
任务是 Activity 集合,按 LIFO 排成返回栈。四种启动模式:standard(默认新建)、singleTop(栈顶有则复用)、singleTask(全局唯一清上方)、singleInstance(独占任务,少用)。Intent flags 能临时控制。Compose 用 Navigation 组件管理自己的导航栈,返回键由 BackHandler 处理。下一节学 Activity 间数据传递。