在日常开发过程中,只要涉及到activity,那么对task相关的东西总会或多或少的接触到,不过对task相关的一些配置的作用一直理解的还不是很透彻,官方文档在细节上说的也不够清楚,要透彻理解还是得自己写demo实践检验,所以便有了这篇总结。

task的概念

参考Tasks and Back Stack

查看设备当前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是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是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。
  • 从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浏览器是两个不同的应用(在“最近应用”的列表中可以看出来)。

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标记)。

参考资料

Android Task 相关的更多相关文章

  1. Android总结篇系列:Activity Intent Flags及Task相关属性

    同上文一样,本文主要引用自网上现有博文,并加上一些自己的理解,在此感谢原作者. 原文地址: http://blog.csdn.net/liuhe688/article/details/6761337 ...

  2. 【转】Android总结篇系列:Activity Intent Flags及Task相关属性

    [转]Android总结篇系列:Activity Intent Flags及Task相关属性 同上文一样,本文主要引用自网上现有博文,并加上一些自己的理解,在此感谢原作者. 原文地址: http:// ...

  3. Activity Intent Flags及Task相关属性

    转自http://www.cnblogs.com/lwbqqyumidi/p/3775479.html 今天我们来讲一下Activity的task相关内容. 上次我们讲到Activity的四种启动模式 ...

  4. 基础总结篇之三:Activity的task相关

    http://blog.csdn.net/liuhe688/article/details/6761337 古人學問無遺力,少壯工夫老始成.紙上得來終覺淺,絕知此事要躬行.南宋.陸遊<冬夜讀書示 ...

  5. Activity的task相关 详解

    task是一个具有栈结构的容器,可以放置多个Activity实例.启动一个应用,系统就会为之创建一个task,来放置根Activity:默认情况下,一个Activity启动另一个Activity时,两 ...

  6. android 技术相关Blog

    android 技术相关 LVXIANGAN的专栏 http://blog.csdn.net/LVXIANGAN/article/category/1101038 Android NFC 开发实例 h ...

  7. Android Studio相关的坑

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  8. Android View相关知识问答

    Android View相关核心知识问答 Activity Window View之间的三角关系 你真的了解View的坐标吗? 在渲染前获取 View 的宽高 5种手势工具类 浅析Android的窗口

  9. Android UI相关开源项目库汇总

    最近做了一个Android UI相关开源项目库汇总,里面集合了OpenDigg 上的优质的Android开源项目库,方便移动开发人员便捷的找到自己需要的项目工具等,感兴趣的可以到GitHub上给个st ...

随机推荐

  1. IOS-tableViewCell重用机制

    IOS-tableViewCell重用机制 首先介绍tableViewCell原生cell的使用和重用机制 使用dequeueReusableCellWithIdentifier方法,这个方法会从缓存 ...

  2. git 指令汇总

    学习git过程中整理的笔记: git add 添加文件到暂存区: git commit -m "更改说明" 提交文件更改: git status 查看当前文件状态: git dif ...

  3. Ant工具

    Ant工具 Ant是一种基于Java的build工具.理论上来说,它有些类似于(Unix)C中的make ,但没有make的缺陷.目前的最新版本为:Ant 1.9.4[1] .   Ant的概念 当一 ...

  4. Hibernate 的HQL语句,初级

    这里讲解简单的HQL语句,因为很多比较复杂的外查询,用一般的查询很难完成 所以这里需要使用HQL @Test public void selquery(){ System.out.printf(&qu ...

  5. Struts2默认拦截器配置

    http://blog.csdn.net/axin66ok/article/details/7321430

  6. 提供他人class文件

    1.考虑的问题,提供的文件是否依赖于其他jar包. 例如:解析html简历时,依赖于Jsoup包.

  7. ios手势复习值之换图片-转场动画(纯代码)

    目标:实现通过手势进行图片的切换   通过左扫右扫 来实现(纯代码) 添加三个属性 1uiImageView 用来显示图片的view 2 index 用来表示图片的索引 3 ISLeft 判断是不是向 ...

  8. idea 配置node Run

    1.node 2.nodemon 支持热部署 3.supervisor  支持执部署

  9. java中的继承要点

    java的一大特性既是:继承. 1.因为有了一个子类继承了一个父类,才有了后面的多态. 2.类的继承,不要为了节省代码,为了继承而继承,把那个没有任何相关的类链接在一起,继承必须用在 is a,就是例 ...

  10. jQuery慢慢啃之事件(七)

    1.ready(fn)//当DOM载入就绪可以查询及操纵时绑定一个要执行的函数. $(document).ready(function(){ // 在这里写你的代码...}); 使用 $(docume ...