Activity启动模式——standard,singleTop,singleTop,singleInstance(译)

原文:Understand Android Activity’s launchMode: standard, singleTop, singleTask and singleInstance

声明启动模式

可以在AndroidManifest.xml文件中声明启动模式。

1
2
3
4
<activity
android:name=".SingleTaskActivity"
android:label="singleTask launchMode"
android:launchMode="singleTask">

standard

默认的启动模式。
这种模式下,随着intent传入,会新建一个Activity实例,无论之前是否已经有该Activity的实例。
但注意,android5.0-Lollipop前后,这种模式下,task的表现有区别。

android5.0之前

新建的Activity会放在同一个task下Activity栈的顶部。
standard_pre_lollipop
比如我们希望分享一个图片的时候,即使前后两个Activity是来自不同的应用,也会放在同一个task中。
standard_pre_lollipop_share
同时在task管理器中可以看到:
standard_pre_lollipop_task_manager

android5.0之后

如果两个Activity来自不同的应用,那就跟之前相同。
standard_after_lollipop
但如果两个Activity来自不同的应用,就会新建一个task了。
standard_after_lollipop_different_app
这个时候再看task管理器:
standard_after_lollipop_task_manager
这是因为android5.0以后的task管理器有修改以更直观有效。

singleTop

这个模式,几乎与standard类似,就是可以无限创建Activity。唯一的区别就是,如果Activity实例已经在栈顶了,那么就不会创建新的Activity实例了,而是会将intent传入已有的Activity的实例的onNewIntent()方法。
singletop
所以,在singleTop模式下,必须在onCreate()和onNewIntent()中都处理传入的intent。

singeTask

singleTask只允许一个Activity实例。如果已经存在Activity实例,那么task中的这个实例会被置顶,这个过程中,Activity栈中在其上的Activity都会被销毁,并且intent会被传给onNewIntent()。如果不存在Activity实例,新的Activity实例会被创建并放在合适的task中。

同一个应用中的情景

如果之前没有Activity实例,那就会创建一个新的并放在栈顶。
singleTask_default
但如果已经存在Activity实例,那么task中的这个实例会被置顶,这个过程中,Activity栈中在其上的Activity都会被销毁,并且intent会被传给onNewIntent()。
singleTask_exist
要注意的是,官方文档中有这么一句话

The system creates a new task and instantiates the activity at the root of the new task.

但通过实验,并没有新建一个task,怎么回事呢?
如果需要如官文所描述,新建一个task,就需要声明taskAffinity属性:

1
2
3
4
5
<activity
android:name=".SingleTaskActivity"
android:label="singleTask launchMode"
android:launchMode="singleTask"
android:taskAffinity="">

这个时候结果如下:
singleTask_task_affinity
singleTask_task_affinity_task_manager
至于要不要用taskAffinity,就要根据实际情况考虑了。

总结:

  1. 设置了”singleTask”启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的任务存在;如果存在这样的任务,它就会在这个任务中启动,否则就会在新任务中启动。因此,如果我们想要设置了”singleTask”启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。
  2. 如果设置了”singleTask”启动模式的Activity不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity实例,如果存在,就会把位于这个Activity实例上面的Activity全部结束掉,即最终这个Activity实例会位于任务的堆栈顶端中。
不同的应用

如果系统中,没有这个Activity的实例,那么,新建Activity的时候,就会创建一个新的task。
singleTaskAnotherApp
singleTaskAnotherApp2
如果这个声明了singleTask的应用已经存在一个task了,切这个task里面没有那个Activity,那么新建的Activity实例会放到这个task的顶部。
singleTaskAnotherAppExist
如果Activity已经存在于那个task,那么,栈上面的Activity实例会被销毁。如果用户按了返回键,就会回到唤起Activity的task。
singleTaskAnotherAppExist2

singeInstance

这个模式跟singleTask类似,系统只能存在一个Activity的实例。唯一的区别就是,singleInstance中,Activity所在的task只能有那个Activity实例,不能有别的Activity。
所以,新建这个Activity的时候,就会创建一个新的task。
singleInstance
这种模式很少用。

Intent Flags

除了在AndroidManifest.xml中声明启动模式,还可以在代码中添加Intent Flags,例如:

1
2
3
Intent intent = new Intent(StandardActivity.this, StandardActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);