安卓 Activity 四种启动模式(Launch Mode)的核心知识点整理
一、启动模式分类与核心概念
模式 | 启动方式 | 实例数量 | 任务栈行为 |
---|---|---|---|
standard | 默认模式 | 每次创建新实例 | 压入启动它的任务栈 |
singleTop | android:launchMode="singleTop" | 栈顶唯一 | 存在于栈顶时复用,否则创建新实例 |
singleTask | android:launchMode="singleTask" | 全局唯一 | 系统中存在则复用并清空其上的 Activity |
singleInstance | android:launchMode="singleInstance" | 全局唯一 | 单独运行在一个任务栈中,不与其他 Activity 共存 |
二、关键特性详解
1. standard 模式
- 特点:
- 每次启动都会创建新实例
- 可以存在多个相同 Activity 实例
- 适合大多数普通 Activity
- 典型场景:商品详情页、新闻内容页
2. singleTop 模式
- 特点:
- 若目标 Activity 在栈顶,直接复用并调用
onNewIntent()
- 不在栈顶时创建新实例
- 若目标 Activity 在栈顶,直接复用并调用
- 典型场景:
- 通知栏点击进入的 Activity
- 搜索结果页(避免重复创建相同搜索结果页)
3. singleTask 模式
- 特点:
- 系统中唯一实例,存在则复用
- 复用时会清空其上的所有 Activity(调用
onNewIntent()
) - 默认在启动它的任务栈中,但可通过
taskAffinity
指定新任务栈
- 典型场景:
- 应用主界面(如微信主界面,按 Home 键后再启动不会创建新界面)
- 浏览器主界面
4. singleInstance 模式
- 特点:
- 单独运行在一个任务栈中
- 不允许其他 Activity 存在于同一任务栈
- 跨应用共享 Activity(如系统闹钟提醒界面)
- 典型场景:
- 闹钟提醒界面
- 来电显示界面
三、常见面试问题
1. 简述四种启动模式的区别
- standard:每次创建新实例,可存在多个相同 Activity
- singleTop:栈顶唯一,复用栈顶实例
- singleTask:全局唯一,复用并清空其上 Activity
- singleInstance:单独任务栈,不与其他 Activity 共存
2. onNewIntent () 的调用时机?
- singleTop:当 Activity 在栈顶,再次启动时调用
- singleTask/singleInstance:当 Activity 被复用时调用
- 注意:需在
onNewIntent()
中调用setIntent(intent)
更新当前 Intent
3. 如何在代码中设置启动模式?
- Manifest 方式:
xml
<activityandroid:name=".MainActivity"android:launchMode="singleTask"/>
- 代码方式(优先级高于 Manifest):
java
Intent intent = new Intent(this, TargetActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); startActivity(intent);
4. FLAG_ACTIVITY_CLEAR_TOP 与 singleTask 的区别?
- FLAG_ACTIVITY_CLEAR_TOP:
- 清空目标 Activity 之上的所有 Activity
- 可能创建新实例(取决于是否设置 FLAG_ACTIVITY_SINGLE_TOP)
- singleTask:
- 自动包含 FLAG_ACTIVITY_CLEAR_TOP 效果
- 不会创建新实例,直接复用
5. singleTask 与 singleInstance 的主要差异?
特性 | singleTask | singleInstance |
---|---|---|
任务栈数量 | 与其他 Activity 共享任务栈 | 独立任务栈 |
能否与其他 Activity 共存 | 可以 | 不可以 |
应用场景 | 应用主界面 | 系统级共享界面 |
6. 启动模式与 TaskAffinity 的关系?
- TaskAffinity:指定 Activity 所属的任务栈名称(默认与应用包名相同)
- 配合场景:
- singleTask 模式下,可通过 TaskAffinity 指定新任务栈
allowTaskReparenting
属性可让 Activity 在不同应用任务栈间移动
7. 如何实现跨应用的 Activity 共享?
- 方案:
- 使用 singleInstance 模式
- 设置
android:exported="true"
允许外部调用 - 示例:
xml
<activityandroid:name=".ShareActivity"android:launchMode="singleInstance"android:exported="true"/>
8. 启动模式对 Activity 生命周期的影响?
- standard/singleTop:正常生命周期流程
- singleTask/singleInstance(复用):
- 原 Activity:onPause → onNewIntent → onResume
- 被清空的 Activity:onPause → onStop → onDestroy
四、代码实战问题
1. 实现一个永不重复创建的搜索结果页
xml
<!-- AndroidManifest.xml -->
<activityandroid:name=".SearchResultActivity"android:launchMode="singleTop"/>
java
// SearchResultActivity.java
@Override
protected void onNewIntent(Intent intent) {super.onNewIntent(intent);setIntent(intent); // 更新当前IntentString query = intent.getStringExtra("query");updateSearchResult(query);
}
2. 模拟微信主界面的启动模式
xml
<activityandroid:name=".MainActivity"android:launchMode="singleTask"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter>
</activity>
- 效果:按 Home 键后再启动应用,直接回到主界面,不会创建新实例
五、最佳实践
避免过度使用 singleInstance:单独任务栈会增加内存开销,且任务栈管理复杂
合理使用 Intent Flag:
FLAG_ACTIVITY_NEW_TASK
:类似 singleTaskFLAG_ACTIVITY_CLEAR_TASK
:清空当前任务栈FLAG_ACTIVITY_NO_HISTORY
:Activity 不会保存在历史栈中
调试工具:
- 使用
adb shell dumpsys activity activities
查看任务栈状态 - Android Profiler 监控 Activity 创建和销毁
- 使用
注意 Fragment 与 Activity 启动模式的配合:
- 若 Activity 为 singleTask,Fragment 需在 onNewIntent 中手动处理数据更新
六、补充高频面试问题
1. 为什么 singleTask 模式下,再次启动会清空其上方的 Activity?这一特性有什么实际用途?
- 原理:singleTask 的设计目标是确保该 Activity 在任务栈中 “独占主导地位”,避免用户在多层 Activity 跳转后,再次启动该 Activity 时需要逐层返回。
- 实际用途:
- 主界面(如微信首页):从任何子页面(聊天页、朋友圈)返回主界面后,子页面应被销毁,避免用户按返回键时重复进入。
- 支付结果页:支付完成后返回订单页,中间的支付流程页面应被清空,防止用户重复操作。
2. 使用 singleInstance 模式的 Activity,启动其他 Activity 时,新 Activity 会进入哪个任务栈?
- 规则:新 Activity 会进入启动它的那个任务栈(即与 singleInstance 所在任务栈不同的默认任务栈)。
- 示例:
若AlarmActivity
(singleInstance,独立任务栈 A)启动DetailActivity
(standard),则DetailActivity
会进入应用默认任务栈 B,而非任务栈 A。此时按返回键,会从DetailActivity
(任务栈 B)直接返回AlarmActivity
(任务栈 A)。
3. Manifest 中设置的 launchMode 与 Intent.addFlags () 设置的启动模式冲突时,以哪个为准?为什么?
- 结论:以
Intent.addFlags()
为准,代码设置的优先级更高。 - 原因:
Manifest 是 “静态配置”,适用于所有启动场景;而代码中的 Flags 是 “动态配置”,可根据不同业务场景灵活修改(例如同一 Activity 在 A 场景用 standard,在 B 场景用 singleTop)。系统设计时优先满足动态需求。
4. 如何让一个 Activity 启动后,按返回键直接退出应用?
- 方案:结合
singleTask
和FLAG_ACTIVITY_CLEAR_TASK
。java
Intent intent = new Intent(this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);
- 原理:
FLAG_ACTIVITY_CLEAR_TASK
会清空目标任务栈,FLAG_ACTIVITY_NEW_TASK
确保创建新任务栈(若不存在),此时栈中只有MainActivity
,按返回键则退出应用。
5. singleTop 模式下,若 Activity 不在栈顶,再次启动会创建新实例,此时新旧实例的生命周期有何差异?
- 新实例:执行完整生命周期(
onCreate() → onStart() → onResume()
)。 - 旧实例:不受影响(继续处于
onPause()
/onStop()
状态,直到被系统回收或用户返回)。 - 示例:
任务栈为A → B → C
(均为 singleTop),启动B
时,会创建新B
实例,栈变为A → B → C → B
,旧B
仍存在于栈中。
6. TaskAffinity 的作用是什么?如何与 singleTask 配合使用?
- TaskAffinity:
定义 Activity “希望” 所属的任务栈名称(默认与应用包名相同),仅当 Activity 被启动到新任务栈时生效(如配合singleTask
或FLAG_ACTIVITY_NEW_TASK
)。 - 与 singleTask 配合:
若为 singleTask 的 Activity 指定不同的TaskAffinity
(如com.example.othertask
),则该 Activity 会运行在名为com.example.othertask
的独立任务栈中,而非默认任务栈。xml
<activityandroid:name=".MyTaskActivity"android:launchMode="singleTask"android:taskAffinity="com.example.othertask"/>
7. 如何检测当前 Activity 的启动模式?有哪些调试方法?
- 代码检测:通过
ActivityManager
获取任务栈信息。java
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1); ComponentName component = tasks.get(0).topActivity; // 栈顶Activity
- adb 命令:
adb shell dumpsys activity activities
→ 查看包含 “launchMode” 的字段。 - Android Studio 工具:
Profiler → CPU / 内存监控 → 查看 Activity 生命周期回调日志,分析实例创建次数。
8. 使用 singleTask 模式可能导致的问题及解决方案?
- 常见问题:
若其他应用通过隐式意图启动该 Activity,可能导致任务栈混乱(如跳转到该 Activity 后,按返回键进入的是其他应用)。 - 解决方案:
- 为 singleTask 的 Activity 设置
taskAffinity
与应用包名不同,避免与其他应用共享任务栈。 - 启动时添加
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
,确保任务栈状态正确。
- 为 singleTask 的 Activity 设置
七、场景分析题
1. 场景:用户从首页(A)进入列表页(B),再进入详情页(C),此时从通知栏点击再次打开首页(A)。若 A 为 singleTask 模式,任务栈会发生什么变化?用户按返回键会回到哪里?
- 任务栈变化:
原栈为A → B → C
,启动 A(singleTask)后,A 上方的 B 和 C 被销毁,栈变为[A]
。 - 返回键行为:按返回键直接退出应用(因栈中只有 A)。
2. 场景:在一个社交 APP 中,消息通知点击后进入聊天页(ChatActivity),要求多次点击不同通知时,若聊天页已在栈顶则复用,否则创建新页。应选择哪种启动模式?
- 答案:singleTop 模式。
- 理由:
- 若用户正在与 A 聊天(ChatActivity 在栈顶),点击 A 的新消息通知,复用当前页并通过
onNewIntent()
更新内容。 - 若用户在其他页面(如首页),点击 B 的消息通知,创建新的 ChatActivity 实例,栈变为
首页 → Chat(B)
。
- 若用户正在与 A 聊天(ChatActivity 在栈顶),点击 A 的新消息通知,复用当前页并通过
八、关键源码与原理(深入理解)
- 启动模式的核心处理类:
ActivityStackSupervisor
和ActivityRecord
,负责管理任务栈和 Activity 实例。 - singleTask 的匹配规则:通过
Intent
的componentName
和taskAffinity
匹配已有实例,若存在则调用moveToFront()
并清空上方 Activity。 - onNewIntent () 的触发逻辑:当
ActivityRecord
被复用(非新创建)时,系统会调用Activity.onNewIntent()
,并传递新的Intent
。