zoukankan      html  css  js  c++  java
  • Android Task 相关

    在日常开发过程中,只要涉及到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标记)。

    参考资料

  • 相关阅读:
    1063. Set Similarity
    A1047. Student List for Course
    A1039. Course List for Student
    最大公约数、素数、分数运算、超长整数计算总结
    A1024. Palindromic Number
    A1023. Have Fun with Numbers
    A1059. Prime Factors
    A1096. Consecutive Factors
    A1078. Hashing
    A1015. Reversible Primes
  • 原文地址:https://www.cnblogs.com/lqstayreal/p/4671774.html
Copyright © 2011-2022 走看看