启动模式四种:标准的standard,栈顶复用singleTop,栈内复用singleTask,单例模式singleInstance。
这次刚好项目中用到了,先说一下具体情况。我这边需要做个页面跳转,很简单的intent,但是从Activity A到Activity B之后,按下返回键,会回到A,这是正常的standard模式的启动,,但是如果我按下了一个自定义按钮,然后用intent跳回A,这时候按下返回键回到了B,再按一下又到了A。这是栈内又三个Activity :ABA。多次启动A,就会创建多个A,这样就重复创建实例了,这个时候我会优先想到启动模式问题(因为简单直接,懒得考虑ActivityResult之类的写起来麻烦的)。
standard模式:谁启动了B,那B就在谁的栈里面,比如A启动了B,那B就在A所在的栈里面,并且在A上面,也就是栈内有AB。同理如果C启动了B,那么栈内就是CB,如果A启动了B,B又启动了C,那么栈内ABC,这个是最简单的,比较好理解。但是会发现当用ApplicationContext启动standard模式的Activity会报错,因为context没有任务栈,这就报错了,这个时候我们要给它制定一个标记位(下文提到),为其创建一个新任务栈。
singleTop模式:栈顶复用,意思就是只要任务栈的最上层是A,就不创建A,但是会执行A的onNewIntent方法。但是不会调用A的onCreate和onStart。简单来说栈内是ABC,要启动的是C,就不会再创建C,就还会是ABC。
singleTask模式:这就是我上面的项目中使用的方式,只要任何一个栈内有A,就不会创建新的A。系统也会调用A的onNewIntent方法,同时还会调用onRestart和之后的方法。但是,如果所需要的任务栈都没有A,那么就会新建一个任务栈,创建一个A然后放到这个新的栈里面。上面说用标记位的方式,也相当于启动了一个singleTask方式的Activity。
1.如果任务栈S1里面是ABC,启动了singleTask的D,D需要的是任务栈S2,那么就会先创建S2,再创建D,再把D放到S2里面。
2.如果任务栈S1里面是ABC,启动了singleTask的D,D需要的是任务栈S1,那么创建D,再把D放到S1里面。
3.如果S1里面是ADBC,启动了singleTask的D,D需要的是任务栈S1,那么复用D,要把D放到栈顶,因为singleTask会clearTop,所以S1里面变成了AD。
4.如果S1里面AB,S2里面CD,CD都是singleTask,那么从B启动D的时候,CD会到S1里面,S1变成ABCD。因为D的后退任务是C,所以C也会进入到栈内。
5.如果S1里面AB,S2里面CD,CD都是singleTask,那么从B启动C的时候,S1变成了ABC,D出栈了。(具体原因之后分析)
singleInstance模式:它相当于一个霸道的singleTask,它拥有singleTask的所有特性,同时强行要求一个任务栈,就是一定会新建一个任务栈单独留给它并且永远只有它一个。跟栈同生共死。
刚才一直在说activity所需要的任务栈,这是因为activity的一个参数TaskAffinity,它标识了一个activity所需任务栈的名字,默认为应用的包名,这个属性主要和singleTask和allowTaskReparenting配对使用,在其他情况下无意义。和allowTaskReparenting配对主要用于应用跳转问题了,不多介绍。
启动模式的设定主要有两个地方,一个是在AndroidMenifest里面,给Activity设定launchMode属性
<activity android:name=".SecondActivity"
android:launchMode="singleTask"/>
另一种是在Intent的时候设置标记位
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
第二种的优先级高于第一种。第一种不能直接设定clearTop,但是第二种无法指定singleInstance模式。