Android `Activity` 常见有四种启动模式和用途
  1. standard
  2. singleTop
  3. singleTask
  4. singleInstance

它们主要解决的问题是:

当启动一个 Activity 时,系统是每次都创建新实例,还是复用已有实例?

配置方式一般是在 AndroidManifest.xml 中:

<activity
    android:name=".MainActivity"
    android:launchMode="standard" />

一、standard:标准模式

1. 特点

standard 是默认启动模式。

每次启动 Activity,都会创建一个新的实例,不管任务栈里是否已经存在这个 Activity。

例如:

启动顺序:
A -> B -> B -> B

任务栈中会变成:

栈顶
B
B
B
A
栈底

每次 startActivity() 都会执行新的:

onCreate()

2. 常见使用场景

适合大多数普通页面。

例如:

  • 新闻详情页
  • 商品详情页
  • 聊天详情页
  • 文章详情页
  • 普通表单页面

比如你从不同文章列表点进不同文章详情:

文章列表 -> 文章详情1 -> 文章详情2 -> 文章详情3

这种情况下每个详情页可以是不同内容,使用 standard 很合理。


3. 示例

<activity
    android:name=".DetailActivity"
    android:launchMode="standard" />

4. 注意点

如果一个页面不希望重复创建,就不要使用 standard

比如登录页、首页、启动页等,如果重复打开多个实例,可能会导致返回栈混乱。


二、singleTop:栈顶复用模式

1. 特点

如果要启动的 Activity 已经在当前任务栈的栈顶,则不会创建新实例,而是复用当前实例,并回调:

onNewIntent(Intent intent)

如果它不在栈顶,仍然会创建新的实例。

例如当前栈:

栈顶
B
A
栈底

此时再次启动 B:

startActivity(new Intent(this, B.class));

因为 B 已经在栈顶,所以不会创建新 B:

栈顶
B
A
栈底

执行:

B.onNewIntent()

但是如果当前栈是:

栈顶
C
B
A
栈底

此时再启动 B,因为 B 不在栈顶,所以会创建新的 B:

栈顶
B
C
B
A
栈底

2. 常见使用场景

适合那些:

页面可能会被连续重复打开,但如果它已经在最上面,就没必要再创建一个。

典型场景:

场景一:通知栏点击进入消息页

比如用户连续点击同一个通知:

通知 -> MessageActivity
通知 -> MessageActivity
通知 -> MessageActivity

如果用 standard,可能创建多个 MessageActivity

如果用 singleTop,当 MessageActivity 已经在栈顶时,就复用它。


场景二:搜索页面

用户在搜索页中再次触发搜索跳转到搜索页,如果页面已经在顶部,就复用当前页面。


场景三:浏览器地址栏页面

当前已经是某个浏览页面,外部再次传入新的 URL,可以用 singleTop 复用栈顶页面,然后在 onNewIntent() 中处理新 URL。


3. 示例

<activity
    android:name=".SearchActivity"
    android:launchMode="singleTop" />

处理新的 Intent:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);

    String keyword = intent.getStringExtra("keyword");
    // 根据新的 keyword 更新页面
}

4. 对应 Intent Flag

singleTop 类似于:

intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

三、singleTask:栈内复用模式

1. 特点

singleTask 表示:

在同一个任务栈中,只允许存在一个该 Activity 实例。

当启动这个 Activity 时:

  • 如果任务栈中不存在它:创建新实例
  • 如果任务栈中已经存在它:复用已有实例,并把它上面的 Activity 全部清除,然后回调 onNewIntent()

例如当前任务栈:

栈顶
D
C
B
A
栈底

如果 B 是 singleTask,此时再次启动 B:

栈顶
B
A
栈底

C、D 会被清除,B 被复用,执行:

B.onNewIntent()

这叫做:

Clear Top + 复用


2. 常见使用场景

适合那些:

在整个任务栈中只应该存在一个实例的核心入口页面。

典型场景:

场景一:首页 MainActivity

很多 App 的首页会配置为 singleTask

比如从通知、推送、Scheme、外部链接再次进入 App 时,希望回到已有首页,而不是重新创建多个首页。

MainActivity -> DetailActivity -> PayActivity

此时收到推送,点击进入 MainActivity,如果 MainActivity 是 singleTask

MainActivity

上面的 DetailActivityPayActivity 会被清掉。

适合“回到首页”的需求。


场景二:登录页 LoginActivity

有些项目会将登录页设计为唯一实例,避免出现多个登录页叠加。

不过登录页是否适合 singleTask 要看业务。

例如 token 失效时,无论当前在哪个页面,都跳到登录页,并清除它上面的页面。


场景三:支付结果入口页

支付结果页、订单确认页等,如果不希望反复创建多个实例,可以考虑 singleTask


场景四:Deep Link / Scheme 入口页

比如外部浏览器打开:

myapp://product?id=100

如果入口 Activity 使用 singleTask,可以复用已有实例,然后在 onNewIntent() 中处理新的参数。


3. 示例

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

处理新 Intent:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);

    String from = intent.getStringExtra("from");
    // 处理新的跳转逻辑
}

4. 注意点

singleTask 会清除目标 Activity 上面的页面。

比如:

MainActivity -> ListActivity -> DetailActivity

如果 MainActivity 是 singleTask,再次启动 MainActivity:

MainActivity

ListActivityDetailActivity 会被销毁。

所以它适合“回到某个根页面”的需求,但不适合普通详情页。


5. 对应 Intent Flag

类似于:

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

但不完全等价,因为 singleTask 还涉及 taskAffinity 和任务栈选择。


四、singleInstance:单实例独立栈模式

1. 特点

singleInstancesingleTask 更严格。

特点:

  1. 全局只允许存在一个该 Activity 实例
  2. 该 Activity 独占一个任务栈
  3. 其他 Activity 不会和它在同一个任务栈中

例如启动流程:

A -> B(singleInstance) -> C

任务栈可能是:

任务栈1:
A -> C

任务栈2:
B

B 独占一个任务栈。


2. 常见使用场景

现在实际开发中用得比较少。

适合那些:

需要全局唯一,并且要和其他页面完全隔离的 Activity。

典型场景:

场景一:来电页面

系统电话来电界面类似这种设计。

来电页面需要独立存在,不希望被普通 App 页面干扰。


场景二:闹钟响铃页面

闹钟响铃页可能需要从任何地方唤起,并且保持全局唯一。


场景三:悬浮/独立工具页面

某些独立功能页面,例如全局播放器控制页、独立视频通话页等,可能考虑 singleInstance


场景四:地图导航页面

某些导航类页面需要全局唯一、独立任务栈,也可能使用。

不过一般情况下,singleTask 已经够用。


3. 示例

<activity
    android:name=".CallActivity"
    android:launchMode="singleInstance" />

4. 注意点

singleInstance 会带来任务栈切换问题。

比如:

A -> B(singleInstance) -> C

按返回键时,用户看到的返回路径可能和预期不一样,因为 B 在独立任务栈中。

所以普通业务页面不建议使用 singleInstance


五、四种启动模式对比

启动模式 是否默认 是否复用 复用条件 是否清除上层页面 常见场景
standard 每次都新建 普通页面、详情页
singleTop 目标 Activity 在栈顶 通知页、搜索页、防止连续点击重复打开
singleTask 栈中已有该 Activity 是,清除其上方页面 首页、Scheme 入口、主入口页
singleInstance 全局已有该 Activity 独立任务栈 来电、闹钟、独立视频通话页

六、生命周期回调区别

假设目标 Activity 已经存在并被复用,则不会走:

onCreate()

而是走:

onNewIntent()

通常会执行类似流程:

onPause()
onNewIntent()
onResume()

所以如果你在 singleTopsingleTasksingleInstance 中需要处理新参数,要重写:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);

    // 处理新的 intent 数据
}

注意:

setIntent(intent);

如果你后续还会通过:

getIntent()

获取最新数据,建议调用 setIntent(intent)


七、实际开发怎么选?

1. 普通页面

例如:

  • 商品详情
  • 新闻详情
  • 设置页
  • 列表页

一般用默认:

android:launchMode="standard"

2. 防止重复打开当前页面

例如:

  • 当前已经在搜索页,再次打开搜索页
  • 当前已经在消息页,再次点击通知进入消息页

可以用:

android:launchMode="singleTop"

3. App 首页、主入口

例如:

  • MainActivity
  • 首页 Tab 容器
  • Scheme 分发入口

常用:

android:launchMode="singleTask"

4. 全局独立页面

例如:

  • 来电页
  • 闹钟页
  • 独立通话页

可以考虑:

android:launchMode="singleInstance"

但普通 App 很少用。


八、简单记忆

可以这样记:

standard:
每次都创建新的。

singleTop:
如果在栈顶,就复用。

singleTask:
如果栈里有,就复用,并清掉它上面的页面。

singleInstance:
全局唯一,自己单独一个任务栈。

最常见使用:

普通详情页:standard
防重复点击:singleTop
首页/主入口:singleTask
独立特殊页面:singleInstance
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇