Activity启动模式详解

我们可以通过指定Activity的启动模式,来选择任务栈的具体管理规则。

任务栈

关于栈结构,相信大家都不陌生,它是一个后进先出(Last In First Out)的线性表。

而一个Android应用程序功能通常会被拆分成多个Activity,它们之间通过Intent进行连接。Android系统就是通过栈结构来保存应用程序的Activity,栈底的元素是整个任务栈的发起者。一个合理的任务栈是性能的保证和基础。

当一个App启动时,如果当前环境中不存在该App的任务栈,那么系统就会创建一个任务栈。默认情况下,该App所启动的所有Activity都将在这个任务栈中被管理。这个栈也被称为一个Task,也表示为若干个Activity的集合。需要注意的是,一个Task中的Activity可以来自不同的App,同一个App的Activity也可以不在同一个Task中。

Mainifest启动模式

Mainifest文件中一共提供了四种启动模式:

  • 标准模式(Standard)
  • 栈顶复用模式(SingleTop)
  • 栈内复用模式(SingleTask)
  • 单例模式(SingleInstance)

它们可以在AndroidMainifest中进行设置。

1
2
3
4
5
6
7
8
9
<activity
android:launchMode="启动模式"
//属性
//standard:标准模式
//singleTop:栈顶复用模式
//singleTask:栈内复用模式
//singleInstance:单例模式
//如不设置,Activity的启动模式默认为标准模式(standard)
</activity>

这四种功能都具有不同的功能,接下来一一地来进行介绍。

标准模式(Standard)

Standard是默认的启动模式,如果不指定Activity的启动模式,则使用这种方式启动Activity。

该模式下一个ActivityA启动了另一个ActivityB时,新启动的ActivityB就会置于任务栈的顶端,并处于活动状态,而ActivityA仍然保留在任务栈中,当用户按下返回键或者调用finish()方法时,系统会移除顶部的ActivityB,让后面的ActivityA恢复活动状态。

每次启动Activity,都会创建新的实例,覆盖在原Activity上。如下图所示。
Standard启动示例

栈顶复用模式(SingleTop)

有些情况下,你可能会觉得Standard模式不够合理。有时候Activity明明在最前面了,还是会继续创建多个Activity,这时候你就需要用到SingleTop模式了。

该模式下在启动Activity时,系统会判断当前栈顶的Activity是不是要启动的Activity。如果不是则创建新的Activity;如果是则不会创建,而是直接引用这个Activity。

这种启动模式虽然不会创建新的Activity,但仍会在启动时调用onNewIntent()方法。

栈内复用模式(SingleTask)

SingleTask模式可以保证让某个活动在整个应用程序的上下文中只存在一个实例。

该模式会检测整个栈是否存在当前需要启动的Activity。如果不存在正常创建Activity;如果已存在,则将该Activity置于栈顶,并将该Activity以上的其他Activity都销毁。

如果其他程序以SingleTask模式启动这个Activity,那么它将创建一个新的任务栈。需要注意的是,如果这个Activity已经在后台的一个任务栈中了,那么启动后,后台的这个任务栈将会整个被切换到前台。借助官网的一张图可以很容易地理解这一情况。

SingleTask启动示例

当Activity2以SingleTask模式启动ActivityY时,ActivityY所在任务栈会被整个切换到前台。所以这时按下返回键,会回到ActivityX,而不是Activity1。

依据这个特性,我们可以使用该启动模式来一键关闭当前App的所有activity,具体可以参考一键退出App方法合集

单例模式(SingleInstance)

SingleInstance模式可以保证Activity所在的任务中始终只会有一个Activity,通过这个Activity再打开的其它Activity也会被放入到别的任务当中。系统不会向声明成SingleInstance模式的Activity所在的任务当中再添加其它Activity。

假如我们的App中有一个Activity是允许其他App调用的,而且其他App可以与我们的App共享这个Activity的实例,我们就可以采用这种模式。因为SingleInstance模式会有一个单独的返回栈来管理这个Activity。

如果我们用ActivityA打开了ActivityB,而ActivityB是SingleInstance模式,紧接着再用Activity启动ActivityC。此时按下返回键,会发现回直接从ActivityC返回到了ActivityA。具体如下图所示。

SingleInstance启动示例

Intent Flag启动模式

我们不仅可以在AndroidMainifest中设置Activity启动模式,也可以通过activity.addFlag()的模式进行设置

1
2
activity.addFlag(Intent.FLAG_ACTIVITY_SINGLE_TOP);
activity.addFlag(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FlAG_ACTIVITY_NEW_TASK);

FlAG_ACTIVITY_NEW_TASK

该模式使用一个新的TASK来启动一个Activity,但启动的每个Activity都将在一个新的TASK中。

由于Service中并不存在Activity栈,所以这种模式非常适用于在Service中启动Activity。创建一个新的Activity栈并创建新的Activity实例。

Intent.FLAG_ACTIVITY_SINGLE_TOP

与上面的SingleTop模式相同。

FLAG_ACTIVITY_CLEAR_TOP

与上面的SingleTask模式相同。

FLAG_ACTIVITY_NO_HISTORY

该模式启动Activity,当该Activity启动其他Acitivity后,该Activity就消失了,不会存在于Activity栈中。

比如分别启动ActivityA、ActivityB和ActivityC,其中ActivityB设置了Intent.FLAG_ACTIVITY_NO_HISTORY模式,最终的任务栈中为ActivityA和ActivityC。

清空任务栈

如果用户将任务栈切换到后台之后过了很长一段时间,系统会将这个任务栈除了最底下的Activity之外的其他所有Activity都清除。

用户重新切换这个任务栈回前台,将只能看到最底下的那个Activity。

当然,必要的时候,我们也可以在AndroidMainifest中通过设置相关的属性,来改变系统的这种默认行为。

1
2
3
4
5
<activity
android:alwaysRetainTaskState="true"
//android:clearTaskOnLaunch="true"
//android:finishOnTaskLaunch="true"
</activity>

alwaysRetainTaskState

如果将最底层的那个Activity的这个属性设置为true,那么上面所描述的默认行为就将不会发生。

任务中所有的Activity即使过了很长一段时间之后仍然会被继续保留。

clearTaskOnLaunch

如果将最底层的那个Activity的这个属性设置为true,那么只要用户离开了当前任务,再次返回的时候就会将最底层Activity之上的所有其它Activity全部清除掉。

简单来讲,这就是一种和alwaysRetainTaskState完全相反的工作模式,也是默认模式的增强版。

它保证每次返回任务的时候都会是一种初始化状态,即使用户仅仅离开了很短的一段时间。

finishOnTaskLaunch

与前两个模式不同,这个属性不是作用于整个任务上的,而是作用于单个Activity上。

如果某个Activity将这个属性设置成true,那么用户一旦离开了当前任务,再次返回时这个Activity就会被清除掉。

总结

学习了这么全面的启动模式的知识,相信你一定对Activity任务栈的管理十分的得心应手了。

需要明确的一点是,我们使用启动模式和清理方法,是为了让程序的运行更有效率,有更好的用户体验。

所以使用时一定要根据需求谨慎使用,不能过度滥用,从而导致整个App的栈管理混乱。

Chen wechat
欢迎扫描二维码,订阅我的博客公众号MiracleChen