三三要成为安卓糕手
一:五种启动模式总结
启动模式 | 核心特性 | 实例创建规则 | 任务栈行为 | 典型应用场景 |
---|---|---|---|---|
standard(默认) | 最基础模式,无特殊限制 | 每次启动都会创建新实例,无论栈中是否已有该 Activity 实例 | 新实例进入当前任务栈,按启动顺序堆叠(先进后出) | 新闻详情页、列表项详情等需要多次创建的页面 |
singleTop | 避免栈顶重复实例,优化栈顶复用 | 若目标 Activity 已在任务栈顶部,则重用该实例并调用 onNewIntent() ;否则创建新实例 | 新实例进入当前任务栈;复用实例时保持栈结构不变(仅刷新栈顶) | 搜索页面、通知栏点击跳转的页面(避免连续点击重复创建) |
singleTask | 确保整个任务栈中仅存在一个实例,且可被唤醒至栈顶 | 若栈中已存在该实例,将其移至栈顶并清除其上方所有实例;否则创建新实例并放入新任务栈 | 实例所在任务栈唯一,唤醒时通过调整栈结构保证实例在栈顶 | 银行应用主页、应用的核心功能页(如微信首页,确保全局唯一入口) |
singleInstance | 全局唯一实例,且独占一个独立任务栈,不与其他 Activity 共享 | 整个系统中仅存在一个实例,无论从哪个应用启动,均复用该实例 | 实例位于独立任务栈中,其他任何 Activity 都无法进入此栈 | 视频播放页、闹钟页面(需独立于其他任务,支持多任务切换时不中断) |
singleInstancePerTask(Android 12+) | 每个任务栈中仅一个实例,不同任务栈可存在多个实例,适配多窗口场景 | 同一任务栈中若已有实例则复用;新任务栈启动时会创建新实例 | 每个实例独占所在任务栈,但不同任务栈可包含该 Activity 的不同实例 | 多窗口模式下的工具类页面(如文档编辑器,每个窗口任务可独立拥有一个实例) |
二:准备工作
准备LaunchMode1Activity和LaunchMode2Activity两个类和Standard,按钮和TextView都有相应的监听器,会触发一些事件
public class LaunchMode1Activity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch_mode1);
findViewById(R.id.btn_launch1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳转到自己的页面
// Intent intent = new Intent(LaunchMode1Activity.this, LaunchMode2Activity.class);
Intent intent = new Intent(LaunchMode1Activity.this, LaunchMode2Activity.class);
startActivity(intent);
}
});
findViewById(R.id.tv_launch1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳转到自己的页面
Intent intent = new Intent(LaunchMode1Activity.this, LaunchMode2Activity.class);
startActivity(intent);
}
});
}
}
public class LaunchMode2Activity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch_mode2);
findViewById(R.id.btn_launch2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳转到自己的页面
Intent intent = new Intent(LaunchMode2Activity.this, StandardActivity.class);
startActivity(intent);
}
});
findViewById(R.id.tv_launch2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳转到自己的页面
Intent intent = new Intent(LaunchMode2Activity.this, StandardActivity.class);
startActivity(intent);
}
});
}
}
public class StandardActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_standard);
findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳转到自己的页面
Intent intent = new Intent(StandardActivity.this, StandardActivity.class);
startActivity(intent);
}
});
findViewById(R.id.tv_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳转到自己的页面
// Intent intent = new Intent(StandardActivity.this, LaunchMode1Activity.class);
Intent intent = new Intent(StandardActivity.this, StandardActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
});
}
}
0:lanchMode
在清单中设置它,表示启动模式
1:Standard
标准模式,就是栈的基本特点,Activity先进先出,如果要创建的Activity在栈中已经存在了,也会在创建一个新的Activity扔到栈里面放到栈顶。
2:singTop
singleTop
:如果要启动的 Activity 已经位于任务栈的顶部,则不会创建新实例,而是调用其 onNewIntent()
方法;如果不在栈顶,则会创建新实例栈顶模式
public class StandardActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_standard);
findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳转到自己的页面
Intent intent = new Intent(StandardActivity.this, StandardActivity.class);
startActivity(intent);
}
});
}
}
(1)在栈顶
点击按钮launch1,并不会发生页面跳转(不会创建新StandardActivity实例,因为栈中只存在StandardActivity实例并且它在栈顶)
(2)不在栈顶
second跳转到StandardActivity,尽管栈中已经存在StandardActivity,但它并不在栈顶,所以重新创建一个新的实例,放置栈顶
3:singleTask
单任务模式,需要略改上述代码,就是跳转页面的逻辑那一块
特点:当启动 Activity 时,系统会检查所有任务栈和实例
- 若存在:将该任务栈整体移到前台,并清空该实例上方的所有 Activity(使其成为栈顶),同时调用其
onNewIntent()
方法。 - 若不存在:创建新任务栈和该 Activity 的实例。
举例说明:假设任务栈结构为 [A, B, C, D]
(A 是栈底,D 是栈顶),其中 C 是 singleTask
模式。
当再次启动 C 时:
- 系统会销毁 C 上方的所有 Activity(即 D)
- 最终栈结构变为
[A, B, C]
(C 成为新的栈顶) - C 实例被复用,并调用其
onNewIntent()
方法
这种模式就特别适合app的首页,短视频啊app,点开好多个视频,想返回首页
4:singleInstance
单实例模式
singleTask
的强化版,该 Activity 会独占一个全新的任务栈,且整个系统中只有一个实例;
若已存在实例时,系统会复用已有的实例
核心特性:独享任务栈、全局单实例、重复启动时只调至前台。
使用场景:闹钟,独立的任务栈中去播放视频
-
示例:
- 从应用 A 启动
singleInstance
的 Activity X,会创建任务栈[X]
。 - 从应用 B 再次启动 X 时,直接复用已有的
[X]
任务栈和实例,不会创建新的。
- 从应用 A 启动
动画就像在启动一个新的页面一样
两者的关键区别和总结
特性 | singleTask | singleInstance |
---|---|---|
任务栈 | 可与其他 Activity 共享同一个任务栈 | 独占一个任务栈,不允许其他 Activity 进入 |
实例数量 | 整个系统中唯一实例 | 整个系统中唯一实例 |
启动其他 Activity | 其他 Activity 会进入当前任务栈 | 其他 Activity 会进入新的任务栈 |
singleTask
适合作为应用的核心页面,确保唯一实例并管理任务栈的层级。singleInstance
适合完全独立的功能页面,与其他 Activity 严格隔离。
5:singleInstancePerTask
singleInstance
和 singleInstancePerTask
的核心差异就在于实例唯一性的范围:
singleInstance是全局仅有一个实例;singleInstancePerTask可以在不同的任务栈中存在相同的实例
举例:
- 若 Activity Z 是
singleInstance
,则无论你从「微信任务栈」「浏览器任务栈」还是「相册任务栈」启动 Z,始终只有一个 Z 实例在运行。 - 若 Activity Z 是
singleInstancePerTask
,从「微信任务栈」启动 Z 会创建 Z1 实例(独占一个任务栈),从「浏览器任务栈」启动 Z 会创建 Z2 实例(另一个独占任务栈),Z1 和 Z2 是两个完全独立的实例。
场景需要:在不同任务中保持独立状态——多文档编辑
三:Java控制启动模式
设置单独的启动标志
1:四种Flag标志总结
Intent Flag | 对应 / 关联的 launchMode | 核心行为描述 | 典型应用场景 |
---|---|---|---|
无特殊 Flag(默认) | standard | 每次启动都创建新实例,放入当前任务栈顶。 | 大多数普通页面(如列表项详情、表单页) |
FLAG_ACTIVITY_SINGLE_TOP | singleTop | 若目标 Activity 位于栈顶,则复用该实例(调用 onNewIntent ),否则创建新实例。 | 避免重复启动栈顶 Activity(如通知栏点击进入已在栈顶的详情页) |
FLAG_ACTIVITY_CLEAR_TOP | 与 singleTask 关联 | 若目标 Activity 已在栈中(无论位置),销毁其上方所有 Activity 并复用该实例(调用 onNewIntent )。 | 需要返回某个页面并清除中间页面(如从详情页返回首页并清除所有中间页) |
FLAG_ACTIVITY_NEW_TASK | 与 singleTask /singleInstance 关联 | 为目标 Activity 创建新任务栈(若不存在),作为栈根。 | 从后台服务启动 Activity、跨应用启动 Activity(如从浏览器打开第三方应用页面) |
FLAG_ACTIVITY_REORDER_TO_FRONT | 无直接对应 launchMode | 将栈中已有的目标 Activity 移动到栈顶,不销毁其他 Activity。 | 需将历史页面调至前台但保留栈结构(如多标签页切换、返回最近浏览的页面) |
(系统特殊处理) | singleInstance | 实例独占一个任务栈,全局唯一,跨任务复用同一实例。 | 系统级全局页面(如来电界面、全局搜索) |
(系统特殊处理) | singleInstancePerTask | 每个任务栈中仅一个实例,不同任务栈可有独立实例,各实例独占任务栈(API 31+)。 | 多任务独立页面(如每个文档任务的专属编辑器) |
2:用法
findViewById(R.id.tv_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//跳转到自己的页面
// Intent intent = new Intent(StandardActivity.this, LaunchMode1Activity.class);
Intent intent = new Intent(StandardActivity.this, StandardActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
});