众所周知,Activity有4种启动模式,分别是:Standard、SingleTop、SingleTask和SingleInstance,它们控制了被启动Activity的启动行为。本文将通过具体案例,详细分析这几种模式的差异和使用场景,方便日后查阅。
在展开具体分析之前,我们首先要了解下两个基础知识:Activity任务栈和android:taskAffinity
属性。
基础知识
Activity任务栈(Task)
Activity任务栈(Task)是一个标准的栈结构,具有“First In Last Out”的特性,用于在ActivityManagerService侧管理所有的Activity(AMS通过TaskRecord标识一个任务栈,通过ActivityRecord标识一个Activity)。
每当我们打开一个Activity时,就会有一个Activity组件被添加到任务栈,每当我们通过“back”键退出一个Activity时,就会有一个Activity组件从任务栈出栈。任意时刻,只有位于栈顶的Activity才可以跟用户进行交互。
同一时刻,Android系统可以有多个任务栈;每个任务栈可能有一个或多个Activity,这些Activity可能来自于同一个应用程序,也可能来自于多个应用程序。另外,同一个Activity可能只有一个实例,也可能有多个实例,而且这些实例既可能位于同一个任务栈,也可能位于不同的任务栈。而这些行为都可以通过Activity启动模式进行控制。
在Android系统的多个任务栈中,只有一个处于前台,即前台任务栈,其它的都位于后台,即后台任务栈。后台任务栈中的Activity处于暂停状态,用户可以通过唤起后台任务栈中的任意Activity,将后台任务栈切换到前台。
android:taskAffinity属性
android:taskAffinity
是Activity的一个属性,表示该Activity期望的任务栈的名称。默认情况下,一个应用程序中所有Activity的taskAffinity都是相同的,即应用程序的包名。当然,我们可以在配置文件中为每个Activity指定不同的taskAffinity(只有和已有包名不同,才有意义)。一般情况下,该属性主要和SingleTask启动模式或者android:allowTaskReparenting
属性结合使用(下面会详细介绍),在其他情况下没有意义。
四种启动模式
上面简要介绍了Activity任务栈和android:taskAffinity属性。有了这些基础之后,我们就可以详细介绍Activity的四种启动模式了。
一般情况下,我们在AndroidManifest
配置文件中,为Activity指定启动模式和taskAffinity,如下所示:
<activity
android:name="leon.com.activitylaunchmode.FirstActivity"
android:launchMode="singleTop"
android:taskAffinity="leon.com.activitylaunchmode1"/>
除此之外,我们也可以通过设置Intent的某些标志位来达到相同的效果,关于这些和Activity启动模式相关的标志位,我们会在下篇文章进行介绍。
Standard
标准模式,也是系统的默认模式。该模式下,每次启动Activity,都会创建一个新实例,并且将其加入到启动该Activity的那个Activity所在的任务栈中,所以目标Activity的多个实例可以位于不同的任务栈。例如:ActivityA启动了标准模式的ActivityB,那么ActivityB就会在ActivityA所在的任务栈中。
关于标准模式的Activity,有一个很经典的异常:
当我们通过非Activity的Context(例如:Service)启动标准模式的Activity时,就会有以下异常:
Caused by: Android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
这是因为标准模式的Activity会进入启动它的Activity的任务栈中,但是非Activity的Context又没有任务栈,所以就出错了。解决方案在异常信息中已经给出了:在Intent中添加FLAG_ACTIVITY_NEW_TASK
标志位,这样就会为目标Activity创建新的任务栈。
OK,下面我们通过示例验证下该启动模式,具体步骤如下所示:
- 创建MainActivity,并且在MainActivity的onCreate方法中,打印出当前Activity所在的任务栈ID。
- 设置MainActivity的启动模式为Standard。
- 然后通过MainActivity不断启动MainActivity本身。
经过上述步骤,最终的任务栈如下所示(adb shell dumpsys activity activities):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u6L14bET-1571788241427)(http://ltlovezh.com/Standard模式.png)]
通过MainActivity打印出的日志如下所示:
[外链图片转存失败,源站可能有