Activity Launch Mode(启动模式)
要深入理解Activity的启动方式,首先要了解以下几个概念:
- task(任务) :Android管理Avtivity的基本单位不是Activity,而是有若干个Activity组成的task,task之间是有序的,但相对位置可以调整(当点击正在运行按钮的时候,看到的已经打开的activity列表就是task列表);
- back stack(返回栈) :task内部,activty使用back stack这种数据结构进行管理,我们在屏幕上见到的是第0个task的栈顶activity,back stack中的activity严格按照stack的管理方式,先进后出;
- taskAffinity(任务关联):若干个Activity组成一个task。哪些Activity会组成一个task是会收到多个因素的影响的,包括launchMode、taskAffinity等。默认情况下,activity的taskAffinity属性就是activity所属Application的包名,也可以在AndroidManifest文件中自定义activity标签下的taskAffinity值。taskAffinity在一定程度上起着task id的作用,一般情况下每个task都会对应一个taskAffinity,通常由task中的第一个activity指定。
指定Activity的Launch Mode
指定Activity的Launch Mode有两种方式:
- 通过指定AndroidManifest.xml文件中activity标签中的
android:launchMode=""
- 在调用Context.startActivity方法启动activity之前,调用
Intent.addFlags()
方法为intent设置某些flag
注意:当两种方式同时存在时,后者会覆盖前者
android:launchMode
在AndroidManifest.xml文件中使用android:launchMode=""
来指定launch mode,有四种可选方式:
- standard:标准启动模式,当没有指定的时候,默认使用
- 启动activity所在的task将被置为第0个task,放在最前面
- 被启动activity将被实例化,不管之前已经实例化多少次
- 被启动activity将和启动activity放在同一个task中
- 点击返回键时被启动activity被从task顶端移除并销毁掉
- Android5.0之后有变化???
- singleTop
- 被启动activity如果被实例化过而且在启动activity所在task的栈顶,不会创建新的实例,而是调用已存在实例的
onNewIntent
方法;否则,和standard一致
- 被启动activity如果被实例化过而且在启动activity所在task的栈顶,不会创建新的实例,而是调用已存在实例的
- singleTask
- 如果存在与被启动acitivity同taskAffinity的task,这个task将会被置为第0个task,放在最前面;否则创建一个新的task(taskAffinity与被启动activity相同)放在最前面
- 如果 在与被启动acitivity同taskAffinity的task中 不存在被启动activity的实例,创建新的被启动activity实例,放入与被启动acitivity同taskAffinity的task中
- 如果 在与被启动acitivity同taskAffinity的task中 存在被启动activity的实例,那么这个实例上面的所有activity实例都会被移除并销毁,是被启动activity置于task顶部
- singleInstance
- 被启动activity如果没有被实例化过,会新建一个task,并创建新的被启动activity实例放到这个task中(不管之前有没有同
taskAffinity
的task) - 被启动activity如果已经被实例化过,和singleTask一致
- 被启动activity启动其他activity的时候,新被启动的activity 不会和被启动activity在同一个task中,而是由
android:taskAffinity
指定(行为与加了FLAG_ACTIVITY_NEW_TASK标志一致)
- 被启动activity如果没有被实例化过,会新建一个task,并创建新的被启动activity实例放到这个task中(不管之前有没有同
Intent.addFlags()
Context.startActivity(Intent intent)
方法在被调用之前可以通过给intent设置不同的标志(Intent.addFlags(int flag)
)改变activity的launch mode,主要的标志有以下几种:
- FLAG_ACTIVITY_NEW_TASK:官方文档说与singleTask一致,但是经过实测,是不一致的
- 如果存在 与被启动acitivity同taskAffinity的task,这个task将会被置为第0个task,放在最前面;否则创建一个新的task(taskAffinity与被启动activity相同)放在最前面
- 不管之前有没有被启动activity实例,创建新的被启动activity实例,放入与被启动acitivity同taskAffinity的task中
- FLAG_ACTIVITY_SINGLE_TOP:官方文档说与singleTop一致,实测也是一致的
- FLAG_ACTIVITY_CLEAR_TOP
- 被启动activity如果被实例化过,并且在当前的task1中,不会创建新的实例,而是将原实例上方的所有activity出栈销毁,使原实例置于task顶部
- 这个标志经常与FLAG_ACTIVITY_NEW_TASK一起使用,这样就可以是被启动activity的行为与singleTask完全一致
以下是Intent中可以设置的关于activity的一些标志,但是在官方文档tasks and back stacks部分没有提到,我会在实测之后补充它们的用途
- FLAG_ACTIVITY_BROUGHT_TO_FRONT
- FLAG_ACTIVITY_CLEAR_TASK
- FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
- FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- FLAG_ACTIVITY_FORWARD_RESULT
- FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
- FLAG_ACTIVITY_MULTIPLE_TASK
- FLAG_ACTIVITY_NO_ANIMATION
- FLAG_ACTIVITY_NO_HISTORY
- FLAG_ACTIVITY_NO_USER_ACTION
- FLAG_ACTIVITY_PREVIOUS_IS_TOP
- FLAG_ACTIVITY_REORDER_TO_FRONT
- FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
- FLAG_ACTIVITY_TASK_ON_HOME
混合使用
在官方文档的tasks and back stacks部分,只提到了当前面两种设置activity的launch mode的方式同时存在的时候,在Intent
中setFlags
的方式会覆盖在AndroidManifest
中设置launchMode
的方式,这个很好理解,因为AndroidManifest在应用启动的时候就会被载入,launchMode
对应的各种标志就会被设置,而在Intent
调用addFlags
明显要在后面,相当于启动之前修改了某些标志。
参考资料:
http://developer.android.com/guide/components/tasks-and-back-stack.html
http://www.android-doc.com/guide/components/tasks-and-back-stack.html
- 所谓当前的task,不一定是指启动activity所在的task,当Intent中使用了FLAG_ACTIVITY_NEW_TASK标志以后,当前的task就是包含有被启动activity实例的那个task ↩