从0开始认识android(十二):任务(task)、返回栈(back stack)及Activity启动模式

什么是任务和返回栈
  一项任务就是用户在桌面点击图标启动APP开始,在使用该APP的某个功能过程中所涉及到的一组activity的集合;这组activity按“先进去的后出来”的原则保存在一个容器中,这个容器就叫返回栈,栈的结构可以看成一只桶或一个杯子,都只有一头出口,所以“先进后出”。
  手机桌面是开启一项任务的地方,当用户点击一个APP图标开始就开始了一项任务,如果一个APP之前没被启动过,即系统中不存在这个APP的任务,那么系统会为它新建一项任务,否则的话就用旧的任务。

用户、进程、任务、返回栈的区别
  对手机系统而言,一个APP就是一个用户,不管这个APP是否在运行,它始终存在于系统中。
  而当一个APP被启动后以运行的状态存在于系统中,那么这整个APP对系统而言就是一个新的进程,当系统停止了这个APP的所有活动,这个进程也就消失不在了。
  返回栈和进程的状态有些类似,返回栈是装有一组activity的容器,如果这组activity被用户(人)通过手机返回键依次移出了栈(界面onDestory:可参考上篇文章《从0开始认识android(十一):Activity生命周期》里界面onDestory的几种情形。),那么这个返回栈也不复存在了。

返回栈中的Activity和该返回栈的关系
  在同一返回栈中,可以包含同一个Activity的多个实例。而且,返回栈中Activity的顺序永远不会重新排列,先打开的永远在栈底,后打开的永远在栈顶。
  一般而言,我们在创建或打开一个activity的时候最好不用去管它和它所在的返回栈的关系,用默认的配置就好了,但万一有需求的话,我们该怎么去管理activity和它所在的任务栈的关系呢?
  可以从两方面考虑,一方面就是在清单文件中为activity定义相关属性,另一方面可以给启动activity的intent指定一个指令用于限制目标activity的启动方式。而以下就是清单文件中可定义的标签:
  1、任务亲和关系android:taskAffinity

  与 Activity 有着亲和关系的任务。从概念上讲,具有相同亲和关系的 Activity 归属同一任务(从用户的角度来看,则是归属同一“应用”)。 任务的亲和关系由其根 Activity 的亲和关系确定。
  默认情况下,应用中的所有 Activity 都具有相同的亲和关系。您可以设置该属性来以不同方式组合它们,甚至可以将在不同应用中定义的 Activity 置于同一任务内。 要指定 Activity 与任何任务均无亲和关系,请将其设置为空字符串。
  如果未设置该属性,则 Activity 继承为应用设置的亲和关系(请参阅 元素的 taskAffinity 属性)。 应用默认亲和关系的名称是 < manifest> 元素设置的软件包名称。

  2、启动模式android:launchMode

  有关应如何启动 Activity 的指令。共有四种模式与 Intent 对象中的 Activity 标志(FLAG_ACTIVITY_* 常量)协同工作,以确定在调用 Activity 处理 Intent 时应执行的操作。 这些模式是:
  “standard”
  “singleTop”
  “singleTask”
  “singleInstance”
  默认模式是“standard”。
  如下表所示,这些模式分为两大类,“standard”和“singleTop”Activity 为一类,“singleTask”和“singleInstance”为另一类。使用“standard”或“singleTop”启动模式的 Activity 可多次实例化。 实例可归属任何任务,并且可以位于 Activity 堆栈中的任何位置。 它们通常启动到名为 startActivity() 的任务之中(除非 Intent 对象包含 FLAG_ACTIVITY_NEW_TASK 指令,在此情况下会选择其他任务 — 请参阅 taskAffinity 属性)——意思就是:如果启动它的intent带有FLAG_ACTIVITY_NEW_TASK 标签的话,那么这个activity会优先被安排进入一个新的返回栈;如果启动它的intent没有有FLAG_ACTIVITY_NEW_TASK指令目标而且activity在清单文件中定义了亲和关系,那么这个activity就被安排进具有该亲和关系的返回栈中;否则就被安排进默认的返回栈中。
  相比之下,“singleTask”和“singleInstance”Activity 只能启动任务(不会新建目标activity的实例)。 它们始终位于 Activity 堆栈的根位置。 “singleTask”和“singleInstance”最好只用于定义了ACTION_MAIN和CATEGORY_LAUNCHER意图过滤器的activity。
  “standard”和“singleTop”模式只在一个方面有差异: 每次“standard”Activity 有新的 Intent 时,系统都会创建新的类实例来响应该 Intent。每个实例处理单个 Intent。同理,也可创建新的“singleTop”Activity 实例来处理新的 Intent。 不过,如果目标任务在其堆栈顶部已有一个 Activity 实例,那么该实例将接收新 Intent(通过调用 onNewIntent());此时不会创建新实例。在其他情况下 — 例如,如果“singleTop”的一个现有实例虽在目标任务内,但未处于堆栈顶部,或者虽然位于堆栈顶部,但不在目标任务中 — 则系统会创建一个新实例并将其推送到堆栈上。
  同理,如果您向上导航到当前堆栈上的某个 Activity,该行为由父 Activity 的启动模式决定。 如果父 Activity 有启动模式 singleTop(或 up Intent 包含 FLAG_ACTIVITY_CLEAR_TOP),则系统会将该父项置于堆栈顶部,并保留其状态。 导航 Intent 由父 Activity 的 onNewIntent() 方法接收。 如果父 Activity 有启动模式 standard(并且 up Intent 不包含 FLAG_ACTIVITY_CLEAR_TOP),则系统会将当前 Activity 及其父项同时弹出堆栈,并创建一个新的父 Activity 实例来接收导航 Intent。
  “singleTask”和“singleInstance”模式同样只在一个方面有差异: “singleTask”Activity 允许其他 Activity 成为其任务的组成部分。 它始终位于其任务的根位置,但其他 Activity(必然是“standard”和“singleTop”Activity)可以启动到该任务中。 相反,“singleInstance”Activity 则不允许其他 Activity 成为其任务的组成部分。它是任务中唯一的 Activity。 如果它启动另一个 Activity,系统会将该 Activity 分配给其他任务 — 就好像 Intent 中包含 FLAG_ACTIVITY_NEW_TASK 一样。
  这里写图片描述
  如上表所示,standard 是默认模式,并且适用于大多数的 Activity 类型。对许多类型的 Activity 而言,SingleTop 也是一个常见并且有用的启动模式。 其他模式 — singleTask 和 singleInstance - 不适合 大多数应用因为它们所形成的交互模式可能让用户感到陌生,并且与大多数其他应用迥异。

  3、允许更改父项(任务)android:allowTaskReparenting

  当启动 Activity 的任务接下来转至前台时,Activity 是否能从该任务转移至与其有亲和关系的任务 —“true”表示它可以转移,“false”表示它仍须留在启动它的任务处。
  如果未设置该属性,则对 Activity 应用由 元素的相应 allowTaskReparenting 属性设置的值。 默认值为“false”。
  正常情况下,当 Activity 启动时,会与启动它的任务关联,并在其整个生命周期中一直留在该任务处。您可以利用该属性强制 Activity 在其当前任务不再显示时将其父项更改为与其有亲和关系的任务。该属性通常用于使应用的 Activity 转移至与该应用关联的主任务。
  例如,如果电子邮件包含网页链接,则点击链接会调出可显示网页的 Activity。 该 Activity 由浏览器应用定义,但作为电子邮件任务的一部分启动。 如果将其父项更改为浏览器任务(父项=任务),它会在浏览器下一次转至前台时显示,当电子邮件任务再次转至前台时则会消失。
  Activity 的亲和关系由 taskAffinity 属性定义。 任务的亲和关系通过读取其根 Activity 的亲和关系来确定。因此,按照定义,根 Activity 始终位于具有相同亲和关系的任务之中。 由于具有“singleTask”或“singleInstance”启动模式的 Activity 只能位于任务的根,因此更改父项仅限于“standard”和“singleTop”模式。

 4、清除根Activity以上的界面android:clearTaskOnLaunch
 

  是否每当从主屏幕重新启动任务时都从中移除根 Activity 之外的所有 Activity —“true”表示始终将任务清除到只剩其根 Activity;“false”表示不做清除。 默认值为“false”。该属性只对启动新任务的 Activity(根 Activity)有意义;对于任务中的所有其他 Activity,均忽略该属性。
  当值为“true”时,每次用户再次启动任务时,无论用户最后在任务中正在执行哪个 Activity,也无论用户是使用返回还是主屏幕按钮离开,都会将用户转至任务的根 Activity。 当值为“false”时,可在某些情况下清除任务中的 Activity(请参阅 alwaysRetainTaskState 属性),但并非一律可以。
  例如,假定有人从主屏幕启动了 Activity P,然后从那里转到 Activity Q。该用户接着按了主屏幕按钮,然后返回到 Activity P。正常情况下,用户将看到 Activity Q,因为那是其最后在 P 的任务中执行的 Activity。 不过,如果 P 将此标志设置为“true”,则当用户按下主屏幕将任务转入后台时,其上的所有 Activity(在本例中为 Q)都会被移除。 因此用户返回任务时只会看到 P。
  如果该属性和 allowTaskReparenting 的值均为“true”,则如上所述,任何可以更改父项的 Activity 都将转移到与其有亲和关系的任务;其余 Activity 随即被移除。

  5、始终保存Activity的状态android:alwaysRetainTaskState

  系统是否始终保持 Activity 所在任务的状态 —“true”表示保持,“false”表示允许系统在特定情况下将任务重置到其初始状态。 默认值为“false”。该属性只对任务的根 Activity 有意义;对于所有其他 Activity,均忽略该属性。
  正常情况下,当用户从主屏幕重新选择某个任务时,系统会在特定情况下清除该任务(从根 Activity 之上的堆栈中移除所有 Activity)。 系统通常会在用户一段时间(如 30 分钟)内未访问任务时执行此操作。
  不过,如果该属性的值是“true”,则无论用户如何到达任务,将始终返回到最后状态的任务。 例如,在网络浏览器这类存在大量用户不愿失去的状态(如多个打开的标签)的应用中,该属性会很有用。

  6、启动时关闭对应的 activity,android:finishOnTaskLaunch

  每当用户再次启动其任务(在主屏幕上选择任务)时,是否应关闭(完成)现有 Activity 实例 —“true”表示应关闭,“false”表示不应关闭。 默认值为“false”。
  如果该属性和 allowTaskReparenting 均为“true”,则优先使用该属性。 Activity 的亲和关系会被忽略。 系统不是更改 Activity 的父项,而是将其销毁。

  以上属性中,可以根据以下两种情况来区分:
  1、主要对任务栈作用的有:
  1.1、taskAffinity
  1.2、allowTaskReparenting
  taskAffinity是指定了任务栈,而allowTaskReparenting则是切换任务栈。

  2、主要对单个Activity作用的有:
  2.1、对特殊activity(根activity)作用的有:
  clearTaskOnLaunch:直接清除根activity以上的界面。
  alwaysRetainTaskState:始终保持所在任务栈的界面的状态——离开时什么样,回来时还是什么样。
  2.2、对指定activity作用:
  finishOnTaskLaunch:从任务栈中删除该属性的界面。
  2.3、launchMode。
  
Intent中的启动指令:
  FLAG_ACTIVITY_NEW_TASK:
  对应启动模式中的singleTask,如果已有该activity的任务,则用该任务中的实例中的onNewIntent()方法接受该 intent,否则就新建一个该activity的任务。
  FLAG_ACTIVITY_SINGLE_TOP:
  对应启动模式中的singleTop,如果该activity处于任务栈的顶部,则使用该实例中的onNewIntent()方法接受intent,否则就新建一个该activity的实例。
  FLAG_ACTIVITY_CLEAR_TOP:
  如果该activity处于任务栈的顶部,则使用该实例的onNewIntent()方法接收intent,如果不在任务栈顶部,则干掉其上面的所有activity实例,使其处于栈顶,再通过onNewIntent()方法接收intent。

  最后,需要注意的一点是:intent中的启动指令会覆盖掉activity在清单文件中定义的启动模式。
     

猜你喜欢

转载自blog.csdn.net/jack_bear_csdn/article/details/80474847