前言:
Activity为什么会有启动模式? 我们可以想想Activity作为Android四大组件中使用最多的一个,经常需要使用Activity将界面显示给用户,这也就设计到了Activity的频繁创建新的Activity(切换Activity)或是已经启动的Activity再次启动(切换回来)。尽管Activity有完整的生命周期回调,但系统又是通过什么来管理众多的Activity的呢?答案是Activity任务栈。Activity任务栈是一种栈结构,先进后出,后进先出,通过任务栈结构可以有效地管理众多的Activity并适应不同的功能需求(有些特殊的需求可以通过不同的启动模式来实现)。下面将介绍Activity的四种启动模式(LaunchMode)。
1、standard(标准)模式
如果我们没有指定Activity的启动模式的时候系统默认以standard模式启动我们的Activity,所以我们平时开发的时候也没有去指定Activity的启动模式,但有些特色功能需求需要使用特定的启动模式来完成,我们可以在注册Activity的时候通过launchMode属性来指定特定的启动模式。
在这种模式下,每当我们启动一个Activity的时候,系统都会创建这个Activity的实例,尽管我们之前启动过,如我们在A中启动A,在启动的A中又启动A,那么任务栈中的Activity就是AAA,即会有3个相同的Activity的实例。代码演示如下:
public void next(View v){
startActivity(new Intent(this,MainActivity.class));
}
通过这个按钮的方法启动3次相同的Activity,那么可以通过adb shell dumpsys activity
命令查看任务栈的状态,可以发现任务栈中存在3个MainActivity的实例,这时我们需要点击3次返回键才能推出这个应用 。
adb shell dumpsys activity
2、singleTop(栈顶复用)模式
顶部单一,也就是栈顶单一,意思是保证 Activity的实例在栈顶是单一的,具体点就是当我们以singleTop模式启动一个Activity的时候,如果这个Activity已经在当前栈顶了,那么将不会再次创建这个Activity的实例(相反则会创建),而是直接调用栈顶的那个实例,如栈顶是ABC,这时启动C,则栈顶还是ABC,C还是之前的那个实例,相比standrad模式则同一个任务栈AAA(A的启动模式为singleTop)的情况是不可能存在的了,而会存在ABCA(A的启动模式为singleTop)的情况。
3、singleTask(栈内复用)模式
栈内单一,指的是Activity的实例在栈内是单一的,当然不同栈还可以存在它的实例。同时,这种模式默认具有clearTop的效果,当要启动的Activity在栈中存在实例时,会将这个Activity调至栈顶,并将位于它之上的Activity出栈,如:栈中存在的Activity实例为ABCD,这时如果D启动B,则栈中的情况为AB。而相比singleTop,singleTask中ABCA的情况是不存在了(A的启动模式为singleTask)。
如:这里有四个Activity,MainActivity,SecondActivity,ThirdActivity,FourthActivity。
它们依次启动下一个Activity,其中SecondActivity的启动模式为singleTask:
adb shell dumpsys activity
这时在FourthActivity中启动SecondActivity,再执行adb shell dumpsys Activity
可以看到,这时位于SecondActivity之上的Activity已经全部出栈了,即clearTop的效果。同时taskAffinity属性可以为这种模式的Activity指定任务栈名称(可以和已有的相同,但没意义;名称相同的栈不一定是同一个栈,需要看栈的id是否相同),默认的任务栈名称为应用的包名。
4、singleInstance(栈间复用)模式
栈间复用,单一实例,在这种模式下Activity只能单独位于一个栈中,当再次启动这个Activity的时候不会再创建它的实例了,尽管它们不在同一栈中。可以理解为全局单例,这种模式使得不同应用可以共享一个Activity的实例。
如两个应用A和B,B中启动了singleInstance的Acitivity C,这时A也启动B中的C(可以通过隐式启动),那么C不会再创建新实例而是返回B创建的那个实例。
可以看到两个应用都启动了ThirdActivity,但栈中只有一个ThirdActivity实例。
任务栈及任务栈转移
Activity系统通过任务栈管理Activity,每个Activity都有它的任务栈,默认情况是新启动的Activity所在的任务栈是启动它的那个Activity的那个任务栈。你也许在开发中遇到过如下错误:
这个错误意思是通过startActivity启动一个新的Activity需要一个Activity类型的Context(getApplicationContext就会报错),解决办法是给intent设置一个flag,或是将启动模式设置为singleTask
Intent intent = new Intent(this,SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
Activity还有一个allowTaskReparenting属性,这个属性标识是否允许任务栈转移。如,应用A启动了应用B的ThirdActivity(隐式启动),ThirdActivity的启动模式为standard,allowTaskReparenting属性为true,这时由于B应用尚未启动,所以ThirdActivity不可能在B的任务栈中,而ThirdActivity会在启动它的Activity的那个任务栈(正常情况下,B的Activity是不会跑在A的任务栈中),如下图所示:
可以看到,B的ThirdActivity在A的任务栈中,这时我们按下Home键回到桌面,启动应用B,这时,B不是进入MainActivity,而是显示已经被A打开的ThirdActivity,而此时ThirdActivity所在的任务栈已经被转移了,如下图:
任务栈是否转移跟launchMode,taskAffinity,allowTaskReparenting属性有关,其中singleTask及singleInstance下不会发生任务栈转移。
利用singleTask实现一键返回首页的功能
一键返回首页的功能在开发中很常见,比如一个购物app,从商品首页到商品详情再到最终付款完成,这时要求在付款成功页面返回首页。由于付款成功页面和首页之间存在许多的Activity,这时我们可以将首页Activity的启动模式设置为singleTask,然后在付款成功页面那里添加一个按钮,点击即启动首页Activity即完成了一键返回首页的功能(其他已经打开的Activity已经被关闭了,直接跳到了首页),利用singleTask模式是不是很简单就实现了一键返回首页的功能呢?