Android Activity 启动模式详解

本文最后更新于:2025年2月8日 凌晨

Android 中 Activity 的启动模式是一个很基础但容易让人困惑的概念。这篇文章把四种启动模式彻底讲清楚。

为什么需要启动模式

Android 使用任务栈(Task)来管理 Activity。默认情况下,启动一个新 Activity 就会把它压入栈顶,按返回键就从栈顶弹出。

但有时候这种默认行为会带来问题:

  • 多次点击按钮,创建了十几个相同的 Activity,按返回键要按到手酸
  • 从通知进入页面,返回时不想看到层层嵌套的页面
  • 主页面应该在栈底,不应该重复创建

启动模式就是为了解决这些问题。

四种启动模式

AndroidManifest.xml 里设置:

1
2
3
<activity 
android:name=".MainActivity"
android:launchMode="singleTask" />

1. standard - 标准模式

这是默认模式,也是最简单的模式:每次启动都创建新实例

特点:

  • 不管栈里有没有这个 Activity,都新建一个
  • 新 Activity 压在启动它的 Activity 上面

示例:

假设当前栈是 A → B,从 B 启动 A:

1
2
3
4
启动前: [A, B]
启动后: [A, B, A] // 新建了 A
按返回: [A, B] // 回到 B
再返回: [A] // 回到最初的 A

代码示例:

1
2
3
4
5
// 连续启动三次 MainActivity
for (int i = 0; i < 3; i++) {
startActivity(new Intent(this, MainActivity.class));
}
// 栈里现在有 4 个 MainActivity 实例

适用场景: 大多数普通页面,没有特殊需求就用这个。


2. singleTop - 栈顶复用

特点:

  • 如果目标 Activity 已经在栈顶,就不新建,直接复用
  • 复用时会调用 onNewIntent() 方法

示例:

1
2
3
4
5
6
7
8
9
场景1: 目标在栈顶
当前栈: [A, B]
从 B 启动 B:
结果: [A, B] // 复用 B,不新建

场景2: 目标不在栈顶
当前栈: [A, B]
从 B 启动 A:
结果: [A, B, A] // 新建 A

代码示例:

1
2
3
4
5
6
7
8
9
public class NotifyActivity extends Activity {
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// 复用时走这里,可以获取新传的数据
String msg = intent.getStringExtra("message");
Log.d("TAG", "收到消息: " + msg);
}
}

适用场景: 推送通知跳转的页面、搜索结果页。避免用户多次点击通知产生多个相同页面。


3. singleTask - 栈内复用

特点:

  • 整个栈里只有一个实例
  • 如果栈里已存在,就复用,并且把它上面的 Activity 全部出栈
  • 复用时也会调用 onNewIntent()

示例:

1
2
3
4
5
6
7
8
9
场景1: 栈里已存在
当前栈: [A, B, C, D]
从 D 启动 B(singleTask):
结果: [A, B] // B 上面的 C、D 都被清掉了

场景2: 栈里不存在
当前栈: [A, B]
从 B 启动 C(singleTask):
结果: [A, B, C] // 正常新建

适用场景: 应用的主页面(Home Activity)。比如从任何深层页面点击「首页」,都应该回到主页面,而不是新建一个。

1
2
3
<activity 
android:name=".MainActivity"
android:launchMode="singleTask" />

注意: 由于会清掉上面的 Activity,如果上面有未保存的数据会丢失。


4. singleInstance - 独立任务

特点:

  • Activity 独占一个任务栈
  • 全局唯一,整个系统只有一个实例
  • 其他 Activity 不能进入这个栈

示例:

1
2
3
4
5
6
7
8
9
10
当前: Task1[A, B]
从 B 启动 C(singleInstance):
结果:
Task1: [A, B]
Task2: [C] // C 单独在一个栈

从 C 启动 D(standard):
结果:
Task1: [A, B, D] // D 回到 Task1
Task2: [C]

适用场景: 非常少见。比如来电界面、闹钟提醒界面,需要独立于应用存在。

注意: 按返回键时,如果当前栈清空了,会自动切换到其他任务栈。


对比总结

模式 是否新建 复用条件 对其他 Activity 的影响
standard 总是新建 不复用
singleTop 看情况 目标在栈顶时复用
singleTask 看情况 目标在栈中时复用 目标上方的 Activity 被销毁
singleInstance 最多一个 全局唯一 独占一个任务栈

动态设置启动模式

除了 XML 配置,也可以在代码里设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 类似 singleTop
Intent intent = new Intent(this, TargetActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

// 类似 singleTask,并清空上方 Activity
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

// 新建任务栈
Intent intent = new Intent(this, SpecialActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

实际开发建议

  1. 主页面用 singleTask:确保不会重复创建,返回逻辑清晰
  2. 通知页面用 singleTop:避免重复实例
  3. 一般页面用 standard:简单,不折腾
  4. 慎用 singleInstance:会让返回逻辑变复杂,除非有特殊需求

调试技巧

查看当前任务栈情况:

1
adb shell dumpsys activity activities | grep -A 5 "Running activities"

能看到当前所有任务栈里的 Activity,方便排查问题。


理解了这四种模式,Activity 的跳转和返回逻辑就不再是黑盒了。遇到问题先想想栈里是什么状态,再判断应该用哪种模式。


Android Activity 启动模式详解
http://bestkele.com/2017/08/08/android/activity/
作者
kele
发布于
2017年8月8日
许可协议