一、任务栈(或叫回退栈)
说到Activity的启动模式,必须先了解Activity的任务栈。
- android任务栈又称为
Task
,它是一个栈结构,具有"先进后出,后进先出"的特性,用于存放我们的Activity组件。 - 我们每次打开一个新的Activity或者退出当前Activity都会在
任务栈
中添加或者减少一个Activity,因此一个任务栈
包含了一个Activity的集合, android系统可以通过任务栈
有序地管理每个Activity,并决定哪个Activity与用户进行交互:只有在任务栈
栈顶的Activity才可以跟用户进行交互。 - 在我们退出应用程序时,必须把所有的
任务栈
中所有的Activity清除出栈时,任务栈
才会被销毁。当然任务栈也可以移动到后台, 并且保留了每一个Activity的状态. 可以有序的给用户列出它们的任务, 同时也不会丢失Activity的状态信息。 任务栈的前台后台 - 需要注意的是,一个App中可能不止一个任务栈,某些特殊情况下,单独一个Actvity可以独享一个
任务栈
。还有一点就是一个任务栈
中的Actvity可以来自不同的App,同一个App的Activity也可能不在一个任务栈
中。 - 当
任务栈
最后一个Activity被销毁时,对应的应用程序被关闭,清除任务栈
,但是还会保留应用程序进程(狂点Back退出到Home界面后点击Menu会发现还有这个App的框框。个人理解应该是这个意思),再次点击进入应用会创建新的任务栈
二、四种启动模式
1、standard标准模式
Standard模式是Android的默认启动模式,你不在配置文件中做任何设置,那么这个Activity就是standard模式,这种模式下,Activity可以有多个实例,每次启动Activity,无论任务栈中是否已经有这个Activity的实例,系统都会创建一个新的Activity实例。 standard模式2、singleTop栈顶复用模式
SingleTop模式和standard模式非常相似,主要区别就是当一个singleTop模式的Activity已经位于任务栈的栈顶,再去启动它时,不会再创建新的实例,如果不位于栈顶,就会创建新的实例。 singletop模式3、singleTask栈内复用模式
SingleTask模式的Activity在同一个Task内只有一个实例,如果Activity已经位于栈顶,系统不会创建新的Activity实例,和singleTop模式一样。但Activity已经存在但不位于栈顶时,系统就会把该Activity移到栈顶,并把它上面的activity出栈。 singletask模式4、singleInstance单实例模式
singleInstance模式也是单例的,但和singleTask不同,singleTask只是任务栈内单例,系统里是可以有多个singleTask Activity实例的,而singleInstance Activity在整个系统里只有一个实例,启动一singleInstanceActivity时,系统会创建一个新的任务栈,并且这个任务栈只有他一个Activity。比如,A应用需要启动的MainActivity 是singleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A单独在这个新的任务栈中,如果此时B应用也要激活MainActivity,由于栈内复用的特性,则不会重新创建,而是两个应用共享一个Activity的实例。SingleInstance模式并不常用,如果我们把一个Activity设置为singleInstance模式,你会发现它启动时会慢一些,切换效果不好,影响用户体验。它往往用于多个应用之间,例如一个电视launcher里的Activity,通过遥控器某个键在任何情况可以启动,这个Activity就可以设置为singleInstance模式,当在某应用中按键启动这个Activity,处理完后按返回键,就会回到之前启动它的应用,不影响用户体验。 singleinstance模式三、两种启动模式的使用方式
1、在 Manifest.xml中指定Activity启动模式(静态设置)
在Manifest.xml文件里声明Activity的同时,在launchMode里指定它的启动模式。
<activity android:name=".StandardActivity" android:launchMode="standard"/>
<activity android:name=".SingleTop2Activity" android:launchMode="singleTop"/>
<activity android:name=".SingleTaskActivity" android:launchMode="singleTask"/>
<activity android:name=".SingleInstanceActivity" android:launchMode="singleInstance"/>
2、启动Activity时。在Intent中指定启动模式去创建Activity(动态设置)
在new 一个Intent后,通过Intent的addFlags()
方法去动态指定一个启动模式。
Intent intent = new Intent();
intent.setClass(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
注:如果同时有动态和静态设置,那么动态的优先级更高。
四、Activity常用的Flags
因为Activity的Flag比较多,切勿死记,我们知道一些常用的就够了,须要时再查官方文档
-
Intent.FLAG_ACTIVITY_NEW_TASK
该标志位表示使用singleTask模式来启动一个Activity,与在清单文件指定android:launchMode="singleTask"
效果相同。
-
Intent.FLAG_ACTIVITY_SINGLE_TOP
该标志位表示使用singleTop模式来启动一个Activity,与在清单文件指定android:launchMode="singleTop"
效果相同。
-
Intent.FLAG_ACTIVITY_CLEAR_TOP
具有此标记位的Activity,启动时会将与该Activity在同一任务栈的其他Activity出栈。一般与SingleTask启动模式一起出现。它会完毕SingleTask的作用。但事实上SingleTask启动模式默认具有此标记位的作用
-
Intent.FLAG_ACTIVITY_NO_HISTORY
使用该模式来启动Activity,当该Activity启动其他Activity后,该Activity就被销毁了,不会保留在任务栈中。如A-B,B中以这种模式启动C,C再启动D,则任务栈只有ABD。
-
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
使用该标识位启动的Activity不添加到最近应用列表,也即我们从最近应用里面查看不到我们启动的这个activity。与属性android:excludeFromRecents="true"
效果相同。
五、启动模式与StartActivityForResult的一个坑
我们在开发过程中经常会用到StartActivityForResult方法启动一个Activity,然后在onActivityResult()方法中可以接收到上个页面的回传值,但你有可能遇到过拿不到返回值的情况,那有可能是因为Activity的LaunchMode设置为了singleTask。5.0之后,android的LaunchMode与StartActivityForResult的关系发生了一些改变。两个Activity,A和B,现在由A页面跳转到B页面,看一下LaunchMode与StartActivityForResult之间的关系:
5.0之前 5.0之后
这是因为ActivityStackSupervisor类中的startActivityUncheckedLocked方法在5.0中进行了修改。在5.0之前,当启动一个Activity时,系统将首先检查Activity的launchMode,如果为A页面设置为SingleInstance或者B页面设置为singleTask或者singleInstance,则会在LaunchFlags中加入FLAG_ACTIVITY_NEW_TASK标志,而如果含有FLAG_ACTIVITY_NEW_TASK标志的话,onActivityResult将会立即接收到一个cancle的信息,而5.0之后这个方法做了修改,修改之后即便启动的页面设置launchMode为singleTask或singleInstance,onActivityResult依旧可以正常工作,也就是说无论设置哪种启动方式,StartActivityForResult和onActivityResult()这一组合都是有效的。所以如果你目前正好基于5.0做相关开发,不要忘了向下兼容,这里有个坑请注意避让。
网友评论