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

上面的 DetailActivity、PayActivity 会被清掉。

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


场景二:登录页 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

ListActivity 和 DetailActivity 会被销毁。

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


5. 对应 Intent Flag

类似于:

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

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


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

1. 特点

singleInstance 比 singleTask 更严格。

特点:

  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()

所以如果你在 singleTop、singleTask、singleInstance 中需要处理新参数,要重写:

@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
小恐龙
花!
上一篇
下一篇