在平常开发过程当中,只要涉及到activity,那么对task相关的东西总会或多或少的接触到,不过对task相关的一些配置的做用一直理解的还不是很透彻,官方文档在细节上说的也不够清楚,要透彻理解仍是得本身写demo实践检验,因此便有了这篇总结。html
task的概念
参考Tasks and Back Stackandroid
查看设备当前task的方法
AndroidManifest中activity标签下和task有关的属性
- 此属性用来标记activity应该属于哪一个task。
- 拥有相同affinity的activity从理论上属于同一个task(在用户的角度看来好像这些activity属于同一个应用),一个task的affinity是由其根activity的taskAffinity取值决定的。
- affinity决定了两件事。
- 一个是在使用allowTaskReparenting修饰activity时,activity要从新宿主到哪一个task。
- 另外一个是使用FLAG_ACTIVITY_NEW_TASK启动activity时,activity要放入哪一个task。
- 若是没有给activity设置taskAffinity,默认都会读取application标签下的taskAffinity属性值,若是application标签下也没有设置taskAffinity,那taskAffinity默认值就是manifest标签下设置的包名。
- 不只能够给同一个应用的不一样activity设置不一样的affinity,也能够给不一样应用的activity设置相同的affinity,使它们在用户角度看来好像属于同一个应用。
launchMode有四种取值,与Intent里以FLAG_ACTIVITY_
开头的flag结合,能够对activity的启动达到各类不一样的效果。浏览器
standard
activity默认的启动模式,每次启动一个standard模式的activity时,都新建一个实例。app
singleTop
当前task栈顶存在本activity的实例,直接使用该实例,调用该activity的onNewIntent(),不然新建一个activity的实例入栈。ide
singleTask
当启动一个singleTask模式的activity时,首先会检查是否存在与该activity的taskAffinity相同的task。ui
- 若是存在,那么检查该task栈里是否存在该activity实例。
- 若是存在,则将该task调入前台,销毁在该activity以上的activity,并调用该activity的onNewIntent()。
- 若是不存在,则新建一个该activity实例,并入栈。
- 若是不存在,则新建一个task,再新建该activity实例并放入新建的task中。
- 从该activity再启动其余activity,容许其余activity跟本身处于同一个task栈中,也容许其余activity从新宿主到本activity。
例若有四个activity叫A、B、C、D,其中A、B具备相同的affinity,如今taskA里有A、B,其中A和B是standard。.net
- 从B启动C,C是singleTask,C的affinity和A、B相同,C会进入taskA栈顶。
- 从C启动D,D是standard或singleTop,不论D的affinity是什么,D会进入taskA栈顶。
- 从D启动C,D出栈被销毁,C接收到onNewIntent()
- 从C启动D,D是singleTask,D的affinity和A、B、C相同,D会进入taskA栈顶。
- 从D启动C,D出栈被销毁,C接收到onNewIntent()
- 从C启动D,D是singleTask,D的affinity和A、B、C不一样,D会进入新建的taskB中。
- 从D启动C,taskA调入前台,放在taskB的上面,C接收到onNewIntent()
- 从C启动D,D是singleInstance,D的affinity不管是什么,D会进入新建的taskB中,taskB的affinity为D的affinity。
- 从D启动C,taskA调入前台,放在taskB的上面,C接收到onNewIntent()
- 从B启动C,C是singleTask,C的affinity和A、B不一样,C会进入新建的taskB中。
- 从C启动D,D是standard或singleTop,不论D的affinity是什么,D会进入taskB栈顶。
- 从D启动C,D出栈被销毁,C接收到onNewIntent()
- 从C启动D,D是singleTask,D的affinity和A、B相同,D会进入taskA栈顶。
- 从D启动C,taskB调入前台,放在taskA的上面,C接收到onNewIntent()
- 从C启动D,D是singleTask,D的affinity和A、B不一样但与C相同,D会进入新建的taskB栈顶。
- 从D启动C,D出栈被销毁,C接收到onNewIntent()
- 从C启动D,D是singleTask,D的affinity和A、B不一样且与C也不一样,D会进入新建的taskC中。
- 从D启动C,taskB调入前台,放在taskC的上面,C接收到onNewIntent()
- 从C启动D,D是singleInstance,D的affinity不管是什么,D会进入新建的taskC中,taskC的affinity为D的affinity。
- 从D启动C,taskB调入前台,放在taskC的上面,C接收到onNewIntent()
singleInstance
当启动一个singleInstance的activity时,首先会检查是否存在与该activity的taskAffinity相同的task。翻译
- 若是存在,检查这个task中是否存在该activity的实例。
- 若是存在,则将该task调入前台,并调用该activity实例的onNewIntent()。
- 若是不存在,则新建一个task,再新建该activity实例放入新建的task中,系统容许多个相同affinity的task同时存在。
- 若是不存在,则新建一个task,再新建该activity实例并放入新建的task中。
- 从该activity再启动其余任何activity,都会放到其余task中(新建task或者寻找已存在的task,即便要启动的activity与该activity具备相同的affinity),也不容许其余activity宿主到本task,该activity是task中惟一的activity。
例若有四个activity叫A、B、C、D,其中A、B具备相同的affinity,如今taskA里有A、B,其中A和B是standardexcel
- 从B中启动C,C是singleInstance,C的affinity和A、B相同,C会放入新建的taskB中,taskA和taskB的affinity相同,由于两个task的根activity的affinity相同。
- 从C中启动D,D的affinity和A、B、C相同。
- D是standard、singleTop、singleTask时,D会放入taskA中,taskA调入前台,放在taskB上面。
- D是singleInstance,D会进入新建的taskC中,taskC和taskA、taskB的affinity相同,由于三个task的根activity的affinity相同。
- 从C中启动D,D的affinity和A、B、C不一样,不论D是何种launchMode,D都会进入新建的taskC中,taskC的affinity是D的affinity。
- 从B中启动C,C是singleInstance,C的affinity和A、B不一样,C会放入新建的taskB中,taskA和taskB的affinity不一样,由于两个task的根activity的affinity不一样。
- 从C中启动D,D的affinity和A、B相同。
- D是standard、singleTop、singleTask时,D都会进入taskA中,taskA调入前台,放在taskB上面。
- D是singleInstance,D会进入新建的taskC中,taskC和taskA的affinity相同,由于两个task的根activity的affinity相同。
- 从C中启动D,D的affinity和A、B不一样,不论和C是否相同,D都会进入新建的taskC中,由于C所在的task不容许其余activity的存在,taskC的affinity为D的affinity。
使用场景:
使用singleInstance时,尽可能给此activity设置单独的taskAffinity,以保证此activity处于不一样名的task中,这样在“最近应用”的列表中能够看到这个task。不然若是有相同task名称的task存在,在“最近应用”的列表中就看不到这个含有singleInstance的activity的task了,只能经过代码启动这个activity来切换回这个task中。
而两个不一样的task在用户角度来看是两个不一样的应用,也就是两种不一样的功能,因此使用singleInstance的activity功能上要与其余activity的功能区别较大。而且singleInstance是单例,也就是这个activity是公用的,能够在其余地方启动它来重复使用(能够是被同一个应用的其余地方重复使用,也能够是被其余的应用重复使用)。
例如,UC浏览器中有一个能够浏览office文档的activity(launchMode为singleInstance,taskAffinity也是独立的),这显然不是浏览器的主要功能。在文件管理器中点击一个excel文件(或者word、ppt文档)的时候,能够选择使用UC浏览器的这个activity来打开它,而且从用户角度看起来这个activity和UC浏览器是两个不一样的应用(在“最近应用”的列表中能够看出来)。code
此属性为true的activity被启动后,如有和此activity相同affinity的task转入前台,则此activity会从启动它的task移动到具备相同affinity的这个task。
例如,如今有两个应用分别为appA和appB,appA中有三个activity分别为activityA一、activityA二、activityA3,其中activityA一、activityA2的taskAffinity为taskA,activityA3的taskAffinity为taskB,appB中有一个activity为activityB1,其taskAffinity为taskB。全部activity都是standard模式。
启动appA,默认启动activityA1,再依次启动activityA二、activityA3,此时这三个activity都属于taskA。
按home键回到launcher,此时这三个activity扔都属于taskA。
- 此时若点击appA的图标启动appA,看到的是activityA2,activityA3会进入新建的affinity为taskB的task中。此时全部task的顺序由前到后依次为taskA、Launcher所在的task、taskB。
- 按home键回到launcher,点击appB的图标启动appB,taskB调入前台显示,看到的是activityA3,而不是activityB1。此时全部task的顺序由前到后依次为taskB、Launcher所在的task、taskA。
- 此时若点击appB的图标启动appB,看到的是activityA3,activityA3进入新建的affinity为taskB的task中。此时全部task的顺序由前到后依次为taskB、Launcher所在的task、taskA。taskB中还有activityB1在栈底部,在activityA3中按返回键能够回到activityB1。taskA中仅剩activityA一、activityA2。
若是用户离开一个task已经好久了,系统会在某个时刻清理掉这个task中除了根activity外全部的activity。当用户再次回到这个task,只有根activity被恢复。这样作是由于长期离开一个task,用户颇有可能已经放弃了他以前所作的事情,转而要开始作新的事情,因此只保留根activity。
若根activity上的alwaysRetainTaskState为true,强制保留本task中的全部activity,即便过了很长时间,也不让系统清理task。
例如浏览器打开了不少个tab页,长时间不操做后也要保证再次回来时仍是上次浏览的页面。
与alwaysRetainTaskState相反,若根activity上的clearTaskOnLaunch为true,不论什么时候用户再次从Launcher回到这个task时,除了根activity之外的其余activity都销毁。
此属性为true的activity,不论什么时候用户再次回到这个activity所属的task时,此activity会被销毁。此属性优先级优于allowTaskReparenting。
Intent中和task有关的部分flag
和launchMode的属性值singleTask等效。若是一个Intent中包含此flag,尝试将要启动的activity放在一个新的task中,若是已经有一个task栈里存在目标activity的实例,将此task从后台调到前台来,调用已存在的activity实例的onNewIntent()方法。此flag不能用于startActivityForResult()。
和launchMode的属性值singleTop等效。若是一个Intent中包含此属性,而且要启动的Activity就是当前的Activity(当前task栈顶activity),直接调用该activity的onNewIntent(),不然新建一个activity实例。
若是一个Intent中包含此属性,而且当前task栈存存在目标activity的实例,清除该实例上面的全部的activity。
若是目标activity的launcherMode为standard,且Intent没有添加FLAG_ACTIVITY_SINGLE_TOP标记,则会销毁目标activity再从新建立,不然会重用该实例,调用onNewIntent()。
若是一个Intent中包含此属性,则它转向的那个Activity以及在那个Activity其上的全部Activity都会在task重置时被清除出task,这只发生在task重置的时候,而从Launcher中点击应用图标启动应用的时候会发生task重置(从Launcher启动应用会在Intent中附带一个FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记)。
参考资料