Android activity四种启动模式及taskAffinity属性总结(附例子源码)
Android activity四种启动模式总结
本人目前在看 Android 开发艺术探索 这本书,书中对启动模式的讲解比较详细,所以自己想总结下。
如果各位能认真的看上一遍,相信会对android activity的启动模式会有更加深刻的印象。
Android启动模式:launchMode在多个Activity跳转的过程中扮演着非常重要的作用,它可以决定是否生成新的activity实例,是否重用已存在的activity实例,是否和其他的activity实例公用一个task(任务栈)。
task(任务栈)的概念:task是一个具有栈结构的对象,一个task可以管理多个activity实例,启动一个应用,也就创建一个与之对应的task。task里面的activity是按照先进后出的形式保存的。比如:你打开一个页面,在页面中打开另一个页面,另一个页面退出后,返回的是第一个打开的页面。这就是任务栈的简单原理。
栈顶的概念:只要是页面刚打开,不管他是什么模式的,它都是栈顶页面。
栈低的概念:首先打开的页面位于最底下,然后后面打开的页面依次往上堆。只有最底下的页面关闭,程序才算完成关闭。
启动模式的概念及理解:
1、standard (标准启动模式):是默认的启动模式,不用为其配置android:launchMode属性即可。在这种模式下启动的activity可以被多次实例化,即在同一个task中可以存在多个activity的实例。每次启动standard模式的activity时,都创建activity实例并放入task。
比如:Activity A的启动模式为standard,并且A已经启动,在A中再次启动Activity A,即调用startActivity(new Intent(this, A.class)),会在A的上面再次启动一个A的实例,即当前的task中状态为A-->A。
2、singleTop(栈顶复用模式):需要为其配置android:launchMode = "singleTop"。如果一个以singleTop模式启动的activity的实例已经存在于task的栈顶,那么再次启动这个activity时,不会创建新的实例,而是重用位于栈顶的那个实例,并且会调用该实例的inNewIntent()方法将Intent对象传递到这个实例中。
比如:如果A的启动模式为singleTop,并且A的一个实例已经存在于栈顶中,那么再调用startActivity(new Intent(this, A.class))启动A时,不会再次创建A的实例,而是重用原来的实例,并且调用原来实例的onNewIntent()方法。这时任务栈中还是只有一个A的实例。
注意:如果以singleTop模式启动的acitivity的一个实例已经存在与task中,但是不在栈顶,那么它的行为和standard模式相同,也会创建多个实例。
3、singleTask(栈内复用模式):需要为其配置android:launchMode="singleTask"。如果要启动的Activity(singleTask模式)在task(任务栈)中存在该实例,则不需要创建,只需要把次activity放入栈顶,并把该activity以上的activity实例都移出栈里面;如果不存在该实例就创建该实例放在栈顶。也就是说:一个栈里面只能有一个singleTask模式的activity。
比如:(1)singleTask模式的activity已经存在栈顶,那么跳转到自己的页面,它是不会创建自己的activity实例对象的,这个和SingleTop是一样的。 但如果singleTask模式的Activity已经不在栈顶,那么跳转到自己的页面,它是不会创建自己的activity实例的,而是会直接跳转到自己的实例activity,并且把压在该模式之上的所有activity实例都移除栈,但是该模式底下的activity实例它是没有办法移除的。
(2)如果singleTask模式的activity都还没有创建,那么它会创建它的activity实例对象,并把自己放在栈顶,这个和所有的activity实例对象都是一样的。
注意:一般app主页面都是用SingleTask模式来设计,因为用户点击多次页面的相互跳转后,再点击回到主页,再次点击退出,这时他的实际需求就是要退出程序,而不是一次一次关闭刚才跳转过的页面,最后才退出。
4、singleInstance(全局唯一模式):需要配置android:launchMode="singleInstance"。该模式下,无论是从哪个任务栈中启动activity,只会创建一个目标的activity实例,并且使用一个全新的task栈来加载该activity实例。 可以看出SingleInstance模式比SingleTask模式更加霸道,打开一个SingleTask模式的activity,它如果已经存在,它会把在它之上的该task中的所有activity实例移除。而打开SingleInstance模式的activity,不管它存不存在,它都会新建一个task,把自己放在里面,也就是说刚打开的SingleInstance的activity在自己新建的task中只有自己一个实例对象。
该模式具备singleTask模式的所有特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具有全局唯一性,即整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的Activity实例,除非这个特殊的任务栈被销毁了。以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
SingleInstance模式一般用于资源的共享。比如使用QQ打开软件A和软件B。发现退出QQ程序后,原来打开的程序并没有被关闭。
我们可以在AndroidManifest.xml配置的android:launchMode属性为以上四种之一即可。如图所示:
举例如下:
注意:那个activity启动另一个activity,那么被启动的activity就会在启动的activity所在的栈.
例如:
1.Activity A 要启动Activity B,那么Activity B就会在Activity所在的栈中,并且,Activity B是在Activity A的上面.
现在有两个栈
栈A:有A,B,C 三个标准启动模式的activity
栈B:有D,E 两个singleTask启动模式的activity
这个使用,Activity C要启动Activity E,那么启动之后,栈A中的元素顺序就是:Activity A,Activity B,Activity C,Activity D,Activity E;
这个时候,点击物理返回键返回后,显示的Activity 是Activity D
如果Activity C要启动的是Activity D,启动后,栈A的元素顺序就是:Activity A,Activity B,Activity C,Activity D.
这个时候,点击物理返回按键返回后,显示的就是Activity C;
taskAffinity属性:
那么什么是taskAffinity属性呢,可以简单的理解为任务相关性。
- 这个参数标识了一个Activity所需任务栈的名字,默认情况下,所有Activity所需的任务栈的名字为应用的包名
- 我们可以单独指定每一个Activity的taskAffinity属性覆盖默认值
- 一个任务的affinity决定于这个任务的根activity(root activity)的taskAffinity
- 在概念上,具有相同的affinity的activity(即设置了相同taskAffinity属性的activity)属于同一个任务
- 为一个activity的taskAffinity设置一个空字符串,表明这个activity不属于任何task
很重要的一点taskAffinity属性不对standard和singleTop模式有任何影响,即时你指定了该属性为其他不同的值,这两种启动模式下不会创建新的task(如果不指定即默认值,即包名)
(1) standard和singleTop启动模式都是在原任务栈中新建Activity实例,不会启动新的Task,即使你指定了taskAffinity属性。
(2)singleTask启动模式启动Activity时,首先会根据taskAffinity去寻找当前是否存在一个对应名字的任务栈
- 如果不存在,则会创建一个新的Task,并创建新的Activity实例入栈到新创建的Task中去
- 如果存在,则得到该任务栈,查找该任务栈中是否存在该Activity实例
如果存在实例,则将它上面的Activity实例都出栈,然后回调启动的Activity实例的onNewIntent方法
如果不存在该实例,则新建Activity,并入栈
此外,我们可以将两个不同App中的Activity设置为相同的taskAffinity,这样虽然在不同的应用中,但是Activity会被分配到同一个Task中去。
总结的不好之处 望各位大神给予指正
测试代码传送门:https://github.com/1066893961/LaunchModeTest.git