看了好几次Activity的启动模式,一直没有自己总结,总是看着就忘记了。于是这次打算自己写下来,加深对这部分知识的理解。至于为啥总是看着Activity启动模式,当然我又看的必要性,以后再说对我工作的需要的吧!
本文没有什么创新性,主要参考了博客:Android中Activity四种启动模式和taskAffinity属性详解。
在<activity/>节点中,有个名为:android:launch=的属性,其默认值有4个,分别是standard,singleTop;singleTask和singleInstance。前两种为一组,理解比较简单,个人基本掌握,本文不在阐述。后两种启动模式较为复杂,常常还会引发一些安全问题,下面就这两种模式做一些记录和自己的理解。算是备忘也算是知识积累的过程 。
一、task是什么
简单一句话,task是针对Activity管理提出的概念,task和Activity栈有关,task可以跨应用和快进程实现对Activity的管理。
二、对singleTask启动模式的理解
整个过程基本参考前面说的那篇博文,本文没有向那位作者那样做详细的实验,实验可参考上面链接博文,有空再去修改自己这篇吧!
1、android:taskAffinity=属性
(1)此属性的名字不做翻译解释,翻译显得生硬;
(2)具有相同的affinity的activity(即设置了相同taskAffinity属性的activity)属于同一个任务;
(3)一个任务的affinity决定于这个任务的根activity(root activity)的taskAffinity,即同一个任务的affinity是一样的;
(4)这个属性决定两件事:当activity被re-parent时,它可以被re-paren哪个任务中;当activity以FLAG_ACTIVITY_NEW_TASK标志启动时,它会被启动到哪个任务中。(这个比较难以理解,请结合<activity>中的属性allowTaskReparenting和Intent中的标志 FLAG_ACTIVITY_NEW_TASK加以理解);
(5)默认情况下,一个应用中的所有activity具有相同的taskAffinity,即应用程序的包名。我们可以通过设置不同的taskAffinity属性给应用中的activity分组,也可以把不同的应用中的activity的taskAffinity设置成相同的值;
(6)为一个activity的taskAffinity设置一个空字符串,表明这个activity不属于任何task。
2、只设定android:launchMode=single不设定android:taskAffinity=" "属性时
根据上面第(5)条,taskAffinity可以影响当activity以FLAG_ACTIVITY_NEW_TASK标志启动时,它会被启动到哪个任务中。这句话的意思是,当新启动的activity(SecondActivity)是以FLAG_ACTIVITY_NEW_TASK标志启动时(可以认为FLAG_ACTIVITY_NEW_TASK和singleTask作用相同,当启动模式为singleTask时,framework会将它的启动标志设为FLAG_ACTIVITY_NEW_TASK),framework会检索是否已经存在了一个affinity为com.test.second的任务(即一个TaskRecord对象)
- 如果存在这样的一个任务,则检查在这个任务中是否已经有了一个SecondActivity的实例
b)如果不存在一个SecondActivity的实例,会在这个任务中创建SecondActivity的实例,并调用onCreate()方法;
- 如果不存在这样的一个任务,会创建一个新的affinity为com.test.second的任务,并且将SecondActivity启动到这个新的任务中;
3、同时设定android:launchMode=single和android:taskAffinity="com.test.second"属性时
- 在MainActivity启动SecondActivity时,发现启动模式为singleTask,那么设定他的启动标志为FLAG_ACTIVITY_NEW_TASK;
- 然后获得SecondActivity的taskAffinity,即com.test.second;
- 检查是否已经存在一个affinity为com.test.second的任务,这个任务是不存在的;
- 创建一个新的affinity为com.test.second的任务,并且将SecondActivity启动到这个新的任务中。
framework中对任务和activity‘的调度是很复杂的,尤其是把启动模式设为singleTask或者以FLAG_ACTIVITY_NEW_TASK标志启动时。所以,在使用singleTask和FLAG_ACTIVITY_NEW_TASK时,要仔细测试应用程序。这也是官方文档上的建议。
4、两个不同app中的不同的singleTask模式的Activity的taskAffinity设成相同
过程懒得写了,看上面那篇博客吧,复制了结论:任务(Task)不仅可以跨应用(Application),还可以跨进程(Process)。
5、在同一个任务中具有唯一性
见博客:Android中Activity四种启动模式和taskAffinity属性详解
三、singleInstance启动模式
1、singleInstance启动特点
- 以singleInstance模式启动的Activity具有全局唯一性,即整个系统中只会存在一个这样的实例
- 以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务,被他开启的任何activity都会运行在其他任务中(官方文档上的描述为,singleInstance模式的Activity不允许其他Activity和它共存在一个任务中)
- 被singleInstance模式的Activity开启的其他activity,能够开启一个新任务,但不一定开启新的任务,也可能在已有的一个任务中开启
2、启动过程说明
其实这种行为和singleTask启动时的情况相同。在Activity的启动模式设置为singleTask时,启动时系统会为它加上FLAG_ACTIVITY_NEW_TASK标志,而被singleInstance模式的Activity开启的activity,启动时系统也会为它加上FLAG_ACTIVITY_NEW_TASK标志,所以他们启动时的情况是相同的,上面说明singleTask时已经阐述过,现在重新说明一下:
由于ThirdActivity是被启动模式为singleInstance类型的Activity(即SecondActivity)启动的,framework会为它它加上FLAG_ACTIVITY_NEW_TASK标志,这时 framework会检索是否已经存在了一个affinity为com.test.second(即ThirdActivity的taskAffinity属性)的任务,
- 如果存在这样的一个任务,则检查在这个任务中是否已经有了一个ThirdActivity的实例,
b)如果不存在一个ThirdActivity的实例,会在这个任务中创建ThirdActivity的实例,并调用onCreate()方法
- 如果不存在这样的一个任务,会创建一个新的affinity为com.jg.zhang.androidtasktest.second的任务,并且将ThirdActivity启动到这个新的任务中
1)在SecondActivity启动ThirdActivity时,因为SecondActivity是singleInstance的,所以设定ThirdActivity的启动标志为 FLAG_ACTIVITY_NEW_TASK;
2)然后获得ThirdActivity的taskAffinity,即为包名com.test;
3)检查是否已经存在一个affinity为com.test的任务,这个任务是存在的,就是MainActivity所在的任务,这个任务是在启动 MainActivity时开启的;
4)既然已经存在这个任务,就检索在这个任务中是否存在一个ThirdActivity的实例,发现不存在;
5)在这个已有的任务中启动一个SecondActivity的实例。
1)在SecondActivity启动ThirdActivity时,因为SecondActivity是singleInstance的,那么设定ThirdActivity的启动标志为 FLAG_ACTIVITY_NEW_TASK;
2)然后获得ThirdActivity的taskAffinity,即为com.test.second;
3)检查是否已经存在一个affinity为com.jg.zhang.androidtasktest.second的任务,这个任务是不存在的;
4)创建一个新的affinity为com.jg.zhang.androidtasktest.second的任务,并且将ThirdActivity启动到这个新的任务。
四、总结
我们在操作软件的过程中,一定会涉及界面的跳转。其实在对界面进行跳转时,Android Framework既能在同一个任务中对Activity进行调度,也能以Task为单位进行整体调度。在启动模式为standard或singleTop时,一般是在同一个任务中对Activity进行调度,而在启动模式为singleTask或singleInstance是,一般会对Task进行整体调度。
对Task进行整体调度包括以下操作:
- 按Home键,将之前的任务切换到后台
- 长按Home键,会显示出最近执行过的任务列表
- 在Launcher或HomeScreen点击app图标,开启一个新任务,或者是将已有的任务调度到前台
- 启动singleTask模式的Activity时,会在系统中搜寻是否已经存在一个合适的任务,若存在,则会将这个任务调度到前台以重用这个任务。如果这个任务中已经存在一个要启动的Activity的实例,则清除这个实例之上的所有Activity,将这个实例显示给用户。如果这个已存在的任务中不存在一个要启动的Activity的实例,则在这个任务的顶端启动一个实例。若这个任务不存在,则会启动一个新的任务,在这个新的任务中启动这个singleTask模式的Activity的一个实例。
- 启动singleInstance的Activity时,会在系统中搜寻是否已经存在一个这个Activity的实例,如果存在,会将这个实例所在的任务调度到前台,重用这个Activity的实例(该任务中只有这一个Activity),如果不存在,会开启一个新任务,并在这个新任务中启动这个singleInstance模式的Activity的一个实例。