Android Task 相关
在日常开发过程中,只要涉及到activity,那么对task相关的东西总会或多或少的接触到,不过对task相关的一些配置的作用一直理解的还不是很透彻,官方文档在细节上说的也不够清楚,要透彻理解还是得自己写demo实践检验,所以便有了这篇总结。
task的概念
查看设备当前task的方法
AndroidManifest中activity标签下和task有关的属性
taskAffinity
- 此属性用来标记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
launchMode有四种取值,与Intent里以FLAG_ACTIVITY_开头的flag结合,可以对activity的启动达到各种不同的效果。
standard
activity默认的启动模式,每次启动一个standard模式的activity时,都新建一个实例。
singleTop
当前task栈顶存在本activity的实例,直接使用该实例,调用该activity的onNewIntent(),否则新建一个activity的实例入栈。
singleTask
当启动一个singleTask模式的activity时,首先会检查是否存在与该activity的taskAffinity相同的task。
- 如果存在,那么检查该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。
- 从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是standard或singleTop,不论D的affinity是什么,D会进入taskA栈顶。
- 从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()
- 从C启动D,D是standard或singleTop,不论D的affinity是什么,D会进入taskB栈顶。
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是standard
- 从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。
- 从C中启动D,D的affinity和A、B、C相同。
- 从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。
- 从C中启动D,D的affinity和A、B相同。
使用场景:
使用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浏览器是两个不同的应用(在“最近应用”的列表中可以看出来)。
allowTaskReparenting
此属性为true的activity被启动后,若有和此activity相同affinity的task转入前台,则此activity会从启动它的task移动到具有相同affinity的这个task。
例如,现在有两个应用分别为appA和appB,appA中有三个activity分别为activityA1、activityA2、activityA3,其中activityA1、activityA2的taskAffinity为taskA,activityA3的taskAffinity为taskB,appB中有一个activity为activityB1,其taskAffinity为taskB。所有activity都是standard模式。
启动appA,默认启动activityA1,再依次启动activityA2、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中仅剩activityA1、activityA2。
alwaysRetainTaskState
如果用户离开一个task已经很久了,系统会在某个时刻清理掉这个task中除了根activity外所有的activity。当用户再次回到这个task,只有根activity被恢复。这样做是因为长期离开一个task,用户很有可能已经放弃了他之前所做的事情,转而要开始做新的事情,所以只保留根activity。
若根activity上的alwaysRetainTaskState为true,强制保留本task中的所有activity,即使过了很长时间,也不让系统清理task。
例如浏览器打开了很多个tab页,长时间不操作后也要保证再次回来时还是上次浏览的页面。
clearTaskOnLaunch
与alwaysRetainTaskState相反,若根activity上的clearTaskOnLaunch为true,不论何时用户再次从Launcher回到这个task时,除了根activity以外的其他activity都销毁。
finishOnTaskLaunch
此属性为true的activity,不论何时用户再次回到这个activity所属的task时,此activity会被销毁。此属性优先级优于allowTaskReparenting。
Intent中和task有关的部分flag
FLAG_ACTIVITY_NEW_TASK
和launchMode的属性值singleTask等效。如果一个Intent中包含此flag,尝试将要启动的activity放在一个新的task中,如果已经有一个task栈里存在目标activity的实例,将此task从后台调到前台来,调用已存在的activity实例的onNewIntent()方法。此flag不能用于startActivityForResult()。
FLAG_ACTIVITY_SINGLE_TOP
和launchMode的属性值singleTop等效。如果一个Intent中包含此属性,并且要启动的Activity就是当前的Activity(当前task栈顶activity),直接调用该activity的onNewIntent(),否则新建一个activity实例。
FLAG_ACTIVITY_CLEAR_TOP
如果一个Intent中包含此属性,并且当前task栈存存在目标activity的实例,清除该实例上面的所有的activity。
如果目标activity的launcherMode为standard,且Intent没有添加FLAG_ACTIVITY_SINGLE_TOP标记,则会销毁目标activity再重新创建,否则会重用该实例,调用onNewIntent()。
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
如果一个Intent中包含此属性,则它转向的那个Activity以及在那个Activity其上的所有Activity都会在task重置时被清除出task,这只发生在task重置的时候,而从Launcher中点击应用图标启动应用的时候会发生task重置(从Launcher启动应用会在Intent中附带一个FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记)。
参考资料
- Tasks and Back Stack
- Tasks and Back Stack中文翻译
- AndroidManifest中activity标签API Doc
- Intent API Doc
- Activity的task相关
Android Task 相关的更多相关文章
- Android总结篇系列:Activity Intent Flags及Task相关属性
同上文一样,本文主要引用自网上现有博文,并加上一些自己的理解,在此感谢原作者. 原文地址: http://blog.csdn.net/liuhe688/article/details/6761337 ...
- 【转】Android总结篇系列:Activity Intent Flags及Task相关属性
[转]Android总结篇系列:Activity Intent Flags及Task相关属性 同上文一样,本文主要引用自网上现有博文,并加上一些自己的理解,在此感谢原作者. 原文地址: http:// ...
- Activity Intent Flags及Task相关属性
转自http://www.cnblogs.com/lwbqqyumidi/p/3775479.html 今天我们来讲一下Activity的task相关内容. 上次我们讲到Activity的四种启动模式 ...
- 基础总结篇之三:Activity的task相关
http://blog.csdn.net/liuhe688/article/details/6761337 古人學問無遺力,少壯工夫老始成.紙上得來終覺淺,絕知此事要躬行.南宋.陸遊<冬夜讀書示 ...
- Activity的task相关 详解
task是一个具有栈结构的容器,可以放置多个Activity实例.启动一个应用,系统就会为之创建一个task,来放置根Activity:默认情况下,一个Activity启动另一个Activity时,两 ...
- android 技术相关Blog
android 技术相关 LVXIANGAN的专栏 http://blog.csdn.net/LVXIANGAN/article/category/1101038 Android NFC 开发实例 h ...
- Android Studio相关的坑
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...
- Android View相关知识问答
Android View相关核心知识问答 Activity Window View之间的三角关系 你真的了解View的坐标吗? 在渲染前获取 View 的宽高 5种手势工具类 浅析Android的窗口
- Android UI相关开源项目库汇总
最近做了一个Android UI相关开源项目库汇总,里面集合了OpenDigg 上的优质的Android开源项目库,方便移动开发人员便捷的找到自己需要的项目工具等,感兴趣的可以到GitHub上给个st ...
随机推荐
- 深入分析 Java I/O 的工作机制--转载
Java 的 I/O 类库的基本架构 I/O 问题是任何编程语言都无法回避的问题,可以说 I/O 问题是整个人机交互的核心问题,因为 I/O 是机器获取和交换信息的主要渠道.在当今这个数据大爆炸时代, ...
- Java中Date各种相关用法
Java中Date各种相关用法(一) 1.计算某一月份的最大天数 Java代码 Calendar time=Calendar.getInstance(); time.clear(); time.set ...
- spring 定时任务的 执行时间设置规则
单纯针对时间的设置规则org.springframework.scheduling.quartz.CronTriggerBean允许你更精确地控制任务的运行时间,只需要设置其cronExpressio ...
- 第二篇:python高级之装饰器
python高级之装饰器 python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函 ...
- Hex编码 十六进制编码
import java.io.UnsupportedEncodingException; import java.net.URLEncoder; /** * HEX字符串与字节码(字符串)转换工具 ...
- JQuery的$命名冲突详细解析
在Jquery中,$是JQuery的别名,所有使用$的地方也都可以使用JQuery来替换,如$('#msg')等同于JQuery('#msg')的写法.然而,当我们引入多个js库后,在另外一个js库中 ...
- 如何使用node中的buffer
介绍:Buffer类是一个全局类,是一个比较罕见不需要require( ‘buffer’ )就可以使用的类,Buffer类似与数组也有length, 它里面的元素为16进制的两位数,即 0-255的数 ...
- How to customize authentication to my own set of tables in asp.net web api 2?
ssuming your table is called AppUser, convert your own AppUser domain object to IUser(using Microsof ...
- 那些年,我们一起学WCF--(6)PerCall实例行为
当客户端调用服务器端服务后,服务器端就会为客户端生成一个实例,关于服务实例的分配问题,在WCF中有专门的属性进行设置,可以让所有客户端共享一个实例, 也可以让一个客户端可以拥有多个实例,也可以让一个实 ...
- CI 笔记(easyui js命令)
1. 两种方式加载easyui,一是用class自动渲染,一种是js.建议js. 2. 参考李炎恢的easyui的视频教程.最好的一个视频,对于easyui.