1.首先要了解任务和任务栈的概念

1.1. android任务栈又称为Task,它是一个栈结构,具有后进先出的特性,用于存放我们的Activity组件。 
1.2. 我们每次打开一个新的Activity或者退出当前Activity都会在一个称为任务栈的结构中添加或者减少一个Activity组件,因此一个任务栈包含了一个activity的集合, android系统可以通过Task有序地管理每个activity,并决定哪个Activity与用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。 
1.3. 在我们退出应用程序时,必须把所有的任务栈中所有的activity清除出栈时,任务栈才会被销毁。当然任务栈也可以移动到后台, 并且保留了每一个activity的状态. 可以有序的给用户列出它们的任务, 同时也不会丢失Activity的状态信息。 

1.4. 需要注意的是,一个App中可能不止一个任务栈,某些特殊情况下,单独一个Actvity可以独享一个任务栈。还有一点就是一个Task中的Actvity可以来自不同的App,同一个App的Activity也可能不在一个Task中。

更加详细的简介参考:https://developer.android.google.cn/guide/components/tasks-and-back-stack.html

2.LaunchMode基于自己的理解

2.1首先要知道launchMode有四种加载模式,分别是:

“standard” 
“singleTop” 
“singleTask” 
“singleInstance”

默认模式是“standard”。

那么下面分别介绍每个模式的用途:

2.2standard-标准模式,也是默认的模式

处理的模式如图:

Android启动模式之launchMode一

每次不管任务栈中是否存在某个Activity(例如:AActivity),每次都是在同一个任务栈起启动新的Activity,可以看一下测试的日志如下:

04-18 18:47:59.333 665-665/? I/AActivity onCreate: 131
04-18 18:48:05.572 665-665/com.dress.gold.interconnected.check I/BActivity  onCreate: 131
04-18 18:48:07.288 665-665/com.dress.gold.interconnected.check I/CActivity  onCreate: 131
04-18 18:48:08.153 665-665/com.dress.gold.interconnected.check I/AActivity onCreate: 131
04-18 18:48:13.086 665-665/com.dress.gold.interconnected.check I/BActivity  onCreate: 131
04-18 18:48:14.133 665-665/com.dress.gold.interconnected.check I/CActivity  onCreate: 131

04-18 18:48:15.317 665-665/com.dress.gold.interconnected.check I/AActivity onCreate: 131

输入日志的方法:

Log.i("CActivity  onCreate","" + getTaskId());
getTaskId()方法获取当前任务栈的任务ID,可以帮助我们判断多个Activity是否在同一个任务栈中;

清单文件配置,为每个Activity配置standard模式,也可以不配置使用默认模式:

<activity android:name=".ui.testui.AActivity" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" android:launchMode="standard"/>
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity android:name=".ui.testui.BActivity" android:launchMode="standard"/>
<activity android:name=".ui.testui.CActivity" android:launchMode="standard"/>

2.2singleTop-顶部模式

处理的模式如图:

Android启动模式之launchMode一

若任务栈顶部存在该Activity,则不会重新创建该Activity(例如:CActivity),在onNewIntent方法中接收Intent,可以看一下测试的日志如下:

04-19 22:34:32.581 8803-8803/? I/AActivity onCreate: getTaskId()----137
04-19 22:34:35.874 8803-8803/com.dress.gold.interconnected.check I/BActivity  onCreate: getTaskId()----137
04-19 22:34:37.416 8803-8803/com.dress.gold.interconnected.check I/CActivity  onCreate: getTaskId()----137
04-19 22:34:38.928 8803-8803/com.dress.gold.interconnected.check I/CActivity onNewIntent: getTaskId()----137
04-19 22:34:41.011 8803-8803/com.dress.gold.interconnected.check I/CActivity onNewIntent: getTaskId()----137
04-19 22:34:41.645 8803-8803/com.dress.gold.interconnected.check I/CActivity onNewIntent: getTaskId()----137
04-19 22:34:42.325 8803-8803/com.dress.gold.interconnected.check I/CActivity onNewIntent: getTaskId()----137

若任务栈顶部不存在该Activity,则不会重新创建该Activity(例如:AActivity),可以看一下测试的日志如下:

04-19 22:35:55.513 9447-9447/? I/AActivity onCreate: getTaskId()----138
04-19 22:36:09.617 9447-9447/com.dress.gold.interconnected.check I/BActivity  onCreate: getTaskId()----138
04-19 22:36:10.752 9447-9447/com.dress.gold.interconnected.check I/CActivity  onCreate: getTaskId()----138
04-19 22:36:11.746 9447-9447/com.dress.gold.interconnected.check I/AActivity onCreate: getTaskId()----138
04-19 22:36:12.845 9447-9447/com.dress.gold.interconnected.check I/BActivity  onCreate: getTaskId()----138
04-19 22:36:13.715 9447-9447/com.dress.gold.interconnected.check I/CActivity  onCreate: getTaskId()----138
04-19 22:36:14.264 9447-9447/com.dress.gold.interconnected.check I/AActivity onCreate: getTaskId()----138
04-19 22:36:14.498 9447-9447/com.dress.gold.interconnected.check I/BActivity  onCreate: getTaskId()----138
04-19 22:36:14.964 9447-9447/com.dress.gold.interconnected.check I/CActivity  onCreate: getTaskId()----138
04-19 22:36:15.465 9447-9447/com.dress.gold.interconnected.check I/AActivity onCreate: getTaskId()----138
04-19 22:36:17.181 9447-9447/com.dress.gold.interconnected.check I/BActivity  onCreate: getTaskId()----138
04-19 22:36:20.378 9447-9447/com.dress.gold.interconnected.check I/CActivity  onCreate: getTaskId()----138
04-19 22:36:22.883 9447-9447/com.dress.gold.interconnected.check I/AActivity onCreate: getTaskId()----138

输入日志的方法:

Log.i("CActivity  onCreate","" + getTaskId());
getTaskId()方法获取当前任务栈的任务ID,可以帮助我们判断多个Activity是否在同一个任务栈中;

清单文件配置,为每个Activity配置standard模式,也可以不配置使用默认模式:

<activity android:name=".ui.testui.AActivity" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" android:launchMode="singleTop"/>
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity android:name=".ui.testui.BActivity" android:launchMode="singleTop"/>

<activity android:name=".ui.testui.CActivity" android:launchMode="singleTop"/>

2.3singleTask-单任务模式

处理的模式如图:

Android启动模式之launchMode一

通过测试日志我们就可以分析出虽然我们把Activity都设置singleTask,通过任务ID发现并不是每次都去新建一个任务,

只是在原任务栈上添加Activity,在CActivity启动AActivity时只是把任务栈上的B和C销毁,让A显示在栈顶,A若已经存在则不回重新创建,onNewIntent接收传过来的Intent,

另一种情况则是若C去启动(singleTask模式)的D则会创建D,将D显示在栈顶,A->B->C->D;

总结,有则清除Activity顶部其他的Activity,恢复显示在栈顶,没有则创建新的Activity放在栈顶

可以看一下测试的日志如下:

04-19 22:45:45.668 14050-14050/? I/AActivity onCreate: getTaskId()----143
04-19 22:45:47.600 14050-14050/com.dress.gold.interconnected.check I/BActivity  onCreate: getTaskId()----143
04-19 22:45:48.715 14050-14050/com.dress.gold.interconnected.check I/CActivity  onCreate: getTaskId()----143
04-19 22:45:50.199 14050-14050/com.dress.gold.interconnected.check I/BActivity onDestroy: getTaskId()----143
04-19 22:45:50.208 14050-14050/com.dress.gold.interconnected.check I/AActivity  onNewIntent: getTaskId()----143

04-19 22:45:50.547 14050-14050/com.dress.gold.interconnected.check I/CActivity onDestroy: getTaskId()----143

上面的启动顺序A->B->C->A

04-19 22:46:07.017 14050-14050/com.dress.gold.interconnected.check I/BActivity  onCreate: getTaskId()----143
04-19 22:46:11.096 14050-14050/com.dress.gold.interconnected.check I/CActivity  onCreate: getTaskId()----143
04-19 22:46:12.398 14050-14050/com.dress.gold.interconnected.check I/BActivity onDestroy: getTaskId()----143
04-19 22:46:12.407 14050-14050/com.dress.gold.interconnected.check I/AActivity  onNewIntent: getTaskId()----143

04-19 22:46:12.729 14050-14050/com.dress.gold.interconnected.check I/CActivity onDestroy: getTaskId()----143

上面的启动顺序A->B->C->A

输入日志的方法:

Log.i("CActivity  onCreate","" + getTaskId());
getTaskId()方法获取当前任务栈的任务ID,可以帮助我们判断多个Activity是否在同一个任务栈中;

清单文件配置,为每个Activity配置standard模式,也可以不配置使用默认模式:


<activity android:name=".ui.testui.AActivity" android:launchMode="singleTask">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity android:name=".ui.testui.BActivity" android:launchMode="singleTask"/>
<activity android:name=".ui.testui.CActivity" android:launchMode="singleTask"/>

2.4singleInstance-单例模式

即指每次都是创建一个新的Activity在新的任务中

处理的模式如图:

Android启动模式之launchMode一

通过下面的日志可以发现若启动BActivity的实例没有存在则新开一个任务栈,若存在则不会重新创建Activity,通过onNewIntent方法接收Intent;

总结:就是singleInstance模式的Activity任务栈中只能有一个Activity;

注意事项,若A启动B,在B页面回去后台以后,再回到前台时,在B页面返回按钮则直接回到主屏幕界面,无法回到A;

可以看一下测试的日志如下:

04-19 23:05:06.015 21507-21507/? I/AActivity onCreate: getTaskId()----144

04-19 23:05:20.310 21507-21507/com.dress.gold.interconnected.check I/BActivity  onCreate: getTaskId()----145
04-19 23:05:21.955 21507-21507/com.dress.gold.interconnected.check I/CActivity  onCreate: getTaskId()----146
04-19 23:05:23.445 21507-21507/com.dress.gold.interconnected.check I/AActivity  onNewIntent: getTaskId()----144
04-19 23:05:25.763 21507-21507/com.dress.gold.interconnected.check I/BActivity  onNewIntent: getTaskId()----145
04-19 23:05:27.613 21507-21507/com.dress.gold.interconnected.check I/CActivity onNewIntent: getTaskId()----146
04-19 23:05:32.313 21507-21507/com.dress.gold.interconnected.check I/AActivity  onNewIntent: getTaskId()----144

上面的启动顺序A->B->C->A

输入日志的方法:

Log.i("CActivity  onCreate","" + getTaskId());
getTaskId()方法获取当前任务栈的任务ID,可以帮助我们判断多个Activity是否在同一个任务栈中;

清单文件配置,为每个Activity配置standard模式,也可以不配置使用默认模式:


<activity android:name=".ui.testui.AActivity" android:launchMode="singleInstance">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity android:name=".ui.testui.BActivity" android:launchMode="singleInstance"/>

<activity android:name=".ui.testui.CActivity" android:launchMode="singleInstance"/>

3.launchMode的官方解释

android:launchMode有关应如何启动 Activity 的指令。共有四种模式与 Intent 对象中的 Activity 标志(FLAG_ACTIVITY_* 常量)协同工作,以确定在调用 Activity 处理 Intent 时应执行的操作。 这些模式是:

standard” 
singleTop” 
singleTask” 
singleInstance

默认模式是“standard”。

如下表所示,这些模式分为两大类,“standard”和“singleTop”Activity 为一类,“singleTask”和“singleInstance”为另一类。使用“standard”或“singleTop”启动模式的 Activity 可多次实例化。 实例可归属任何任务,并且可以位于 Activity 堆栈中的任何位置。 它们通常启动到名为 startActivity() 的任务之中(除非 Intent 对象包含 FLAG_ACTIVITY_NEW_TASK 指令,在此情况下会选择其他任务 — 请参阅 taskAffinity 属性)。

相比之下,“singleTask”和“singleInstance”Activity 只能启动任务。 它们始终位于 Activity 堆栈的根位置。此外,设备一次只能保留一个 Activity 实例 — 只允许一个此类任务。

standard”和“singleTop”模式只在一个方面有差异: 每次“standard”Activity 有新的 Intent 时,系统都会创建新的类实例来响应该 Intent。每个实例处理单个 Intent。同理,也可创建新的“singleTop”Activity 实例来处理新的 Intent。 不过,如果目标任务在其堆栈顶部已有一个 Activity 实例,那么该实例将接收新 Intent(通过调用 onNewIntent());此时不会创建新实例。在其他情况下 — 例如,如果“singleTop”的一个现有实例虽在目标任务内,但未处于堆栈顶部,或者虽然位于堆栈顶部,但不在目标任务中 — 则系统会创建一个新实例并将其推送到堆栈上。

同理,如果您向上导航到当前堆栈上的某个 Activity,该行为由父 Activity 的启动模式决定。 如果父 Activity 有启动模式 singleTop(或 upIntent 包含 FLAG_ACTIVITY_CLEAR_TOP),则系统会将该父项置于堆栈顶部,并保留其状态。 导航 Intent 由父 Activity 的 onNewIntent() 方法接收。 如果父 Activity 有启动模式 standard(并且 up Intent 不包含 FLAG_ACTIVITY_CLEAR_TOP),则系统会将当前 Activity 及其父项同时弹出堆栈,并创建一个新的父 Activity 实例来接收导航 Intent。

singleTask”和“singleInstance”模式同样只在一个方面有差异: “singleTask”Activity 允许其他 Activity 成为其任务的组成部分。 它始终位于其任务的根位置,但其他 Activity(必然是“standard”和“singleTop”Activity)可以启动到该任务中。 相反,“singleInstance”Activity 则不允许其他 Activity 成为其任务的组成部分。它是任务中唯一的 Activity。 如果它启动另一个 Activity,系统会将该 Activity 分配给其他任务 — 就好像 Intent 中包含 FLAG_ACTIVITY_NEW_TASK 一样。

用例 启动模式 多个实例? 注释
大多数 Activity 的正常启动 standard 默认值。系统始终会在目标任务中创建新的 Activity 实例并向其传送 Intent。
singleTop 有条件 如果目标任务的顶部已存在一个 Activity 实例,则系统会通过调用该实例的 onNewIntent() 方法向其传送 Intent,而不是创建新的 Activity 实例。
专用启动
(不建议用作常规用途)
singleTask 系统在新任务的根位置创建 Activity 并向其传送 Intent。 不过,如果已存在一个 Activity 实例,则系统会通过调用该实例的 onNewIntent() 方法向其传送 Intent,而不是创建新的 Activity 实例。
singleInstance 与“singleTask"”相同,只是系统不会将任何其他 Activity 启动到包含实例的任务中。 该 Activity 始终是其任务唯一仅有的成员。

如上表所示,standard 是默认模式,并且适用于大多数的 Activity 类型。对许多类型的 Activity 而言,SingleTop 也是一个常见并且有用的启动模式。 其他模式 — singleTask 和 singleInstance - 不适合 大多数应用因为它们所形成的交互模式可能让用户感到陌生,并且与大多数其他应用迥异。

无论您选择哪一种启动模式,请务必在启动期间以及使用返回按钮从其他 Activity 和任务返回该 Activity 时对其进行易用性测试。

如需了解有关启动模式及其与 Intent 标志交互的详细信息,请参阅任务和返回栈文档。

4.其他

4.1Intent中Flag使用

4.1.1事实上在代码中我们并不是一定在AndroidManifest.xml中配置启动模式,也可以通过调用startActivity()方法中设置Flag的方式到达相同的效果;

例如下面的默认配置:

<activity android:name=".ui.testui.AActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity android:name=".ui.testui.BActivity"/>

<activity android:name=".ui.testui.CActivity"/>

A->B->C,可是我们直接回到A页面,而不是创新创建A界面,那么Intent中的Flag就可以实现这种效果,实现代码:

Intent intent = new Intent(this, AActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
 //Intent.FLAG_ACTIVITY_CLEAR_TOP清除AActivity顶部的Activity,Intent.FLAG_ACTIVITY_SINGLE_TOP等于singleTop模式,顶部存在则不创建,在onNewIntent方法中接收Intent
startActivity(intent);

输出日志如下:

04-19 23:34:21.187 915-915/com.dress.gold.interconnected.check I/AActivity onCreate: getTaskId()----148
04-19 23:34:23.218 915-915/com.dress.gold.interconnected.check I/BActivity  onCreate: getTaskId()----148
04-19 23:34:24.052 915-915/com.dress.gold.interconnected.check I/CActivity  onCreate: getTaskId()----148
04-19 23:34:26.202 915-915/com.dress.gold.interconnected.check I/BActivity onDestroy: getTaskId()----148
04-19 23:34:26.218 915-915/com.dress.gold.interconnected.check I/AActivity  onNewIntent: getTaskId()----148
04-19 23:34:26.544 915-915/com.dress.gold.interconnected.check I/CActivity onDestroy: getTaskId()----148

4.1.2还有其他的Flag,例如FLAG_ACTIVITY_NEW_TASK等同于singleTask,当前也可以和FLAG_ACTIVITY_CLEAR_TOP一起使用,但是效果和上面稍有区别,在C启动A使用会把A以上的Activity都销毁掉,同时A也会销毁掉,在A的位置新建一个A;

可以看一下输出日志就明白了:

04-19 23:41:39.462 4461-4461/? I/AActivity onCreate: getTaskId()----149
04-19 23:41:40.918 4461-4461/com.dress.gold.interconnected.check I/BActivity  onCreate: getTaskId()----149
04-19 23:41:41.937 4461-4461/com.dress.gold.interconnected.check I/CActivity  onCreate: getTaskId()----149
04-19 23:41:43.192 4461-4461/com.dress.gold.interconnected.check I/BActivity onDestroy: getTaskId()----149
04-19 23:41:43.199 4461-4461/com.dress.gold.interconnected.check I/AActivity onDestroy: getTaskId()----149
04-19 23:41:43.212 4461-4461/com.dress.gold.interconnected.check I/AActivity onCreate: getTaskId()----149

04-19 23:41:43.676 4461-4461/com.dress.gold.interconnected.check I/CActivity onDestroy: getTaskId()----149

官方解释:

FLAG_ACTIVITY_CLEAR_TOP如果正在启动的 Activity 已在当前任务中运行,则会销毁当前任务顶部的所有 Activity,并通过 onNewIntent() 将此 Intent 传递给 Activity 已恢复的实例(现在位于顶部),而不是启动该 Activity 的新实例。

产生这种行为的 launchMode 属性没有值。

FLAG_ACTIVITY_CLEAR_TOP 通常与 FLAG_ACTIVITY_NEW_TASK 结合使用。一起使用时,通过这些标志,可以找到其他任务中的现有 Activity,并将其放入可从中响应 Intent 的位置。 

:如果指定 Activity 的启动模式为 "standard",则该 Activity 也会从堆栈中移除,并在其位置启动一个新实例,以便处理传入的 Intent。 这是因为当启动模式为 "standard" 时,将始终为新 Intent 创建新实例。 

4.2应用和应用之前交互说明

若X应用启动Y应用,即使Y应用中的AActivity已经启动,若AActivity启动模式设置standard、singleTop或者singleTask模式,则不管Y中是否启动了AActvity,都会在X应用的任务栈添加一个新的AActivity;


参考:https://developer.android.google.cn/guide/components/tasks-and-back-stack.html

相关文章:

  • 2021-09-24
  • 2022-12-23
  • 2021-07-12
  • 2021-11-19
  • 2022-12-23
  • 2021-08-15
  • 2021-08-15
  • 2021-04-28
猜你喜欢
  • 2022-12-23
  • 2021-11-19
  • 2021-11-19
  • 2022-12-23
  • 2021-09-28
  • 2022-01-30
相关资源
相似解决方案