美文网首页
Task和BackStack

Task和BackStack

作者: wind_sky | 来源:发表于2019-07-29 17:05 被阅读0次

    一个Android应用通常包含多个Activity,每个Activity均应围绕用户可以进行的特定操作设计,并且能够启动其他Activity。

    任务(Task)是指在执行特定作业时与用户交互的一系列Activity,这些Activity按照各自的打开顺序排列在堆栈中(即返回栈BackStack)。

    手机的主页是大多数Task的起点,当用户点击应用图标时,该应用的Task将出现在前台,如果应用不存在Task,则会创建一个新Task,并且该应用中的主Activity会作为堆栈中的根Activity打开。

    当前 Activity 启动另一个 Activity 时,该新 Activity 会被推送到堆栈顶部,成为焦点所在。 前一个 Activity 仍保留在堆栈中,但是处于停止状态。Activity 停止时,系统会保持其用户界面的当前状态。 用户按“返回”按钮时,当前 Activity 会从堆栈顶部弹出(Activity 被销毁),而前一个 Activity 恢复执行(恢复其 UI 的前一状态)。 堆栈中的 Activity 永远不会重新排列,仅推入和弹出堆栈:由当前 Activity 启动时推入堆栈;用户使用“返回”按钮退出时弹出堆栈。 因此,返回栈以“后进先出”对象结构运行。


    image.png

    上图展示了back stack的一个工作过程。当所有Activity都从栈中弹出后,Task也不复存在。

    任务是一个有机整体,当用户开始新任务或通过“主页”按钮转到主屏幕时,可以移动到“后台”。 尽管在后台时,该任务中的所有 Activity 全部停止,但是任务的返回栈仍旧不变,也就是说,当另一个任务发生时,该任务仅仅失去焦点而已。

    注:后台可以同时运行多个任务。但是,如果用户同时运行多个后台任务,则系统可能会开始销毁后台 Activity,以回收内存资源,从而导致 Activity 状态丢失。请参阅下面有关 Activity 状态的部分。

    Activity的启动模式:

    启动模式允许程序定义 Activity 的新实例如何与当前任务关联。 我们可以通过两种方法定义不同的启动模式:

    (1)在manifest文件中定义

    在清单文件中声明 Activity 时,您可以使用 <activity> 元素的 launchMode 属性指定 Activity 应该如何与任务关联。launchMode 属性指定有关应如何将 Activity 启动到任务中的指令。您可以分配给 launchMode 属性的启动模式共有四种:

    • standard(默认模式):
      系统在启动 Activity 的任务中创建 Activity 的新实例并向其传送 Intent。Activity 可以多次实例化,而每个实例均可属于不同的任务,并且一个任务可以拥有多个实例。

    • singleTop(栈顶复用模式):
      如果当前任务的顶部已存在 Activity 的一个实例,则系统会通过调用该实例的 onNewIntent() 方法向其传送 Intent,而不是创建 Activity 的新实例。Activity 可以多次实例化,而每个实例均可属于不同的任务,并且一个任务可以拥有多个实例(但前提是位于返回栈顶部的 Activity 并不是 Activity 的现有实例)。

    • singleTask:
      系统创建新任务并实例化位于新任务底部的 Activity。但是,如果该 Activity 的一个实例已存在于一个单独的任务中,则系统会通过调用现有实例的onNewIntent() 方法向其传送 Intent,而不是创建新实例。一次只能存在 Activity 的一个实例。

    :尽管 Activity 在新任务中启动,但是用户按“返回”按钮仍会返回到前一个 Activity。

    • singleInstance:
      与 "singleTask" 相同,只是系统不会将任何其他 Activity 启动到包含实例的任务中。该 Activity 始终是其任务唯一仅有的成员;由此 Activity 启动的任何 Activity 均在单独的任务中打开。

    我们再来看另一示例,Android 浏览器应用声明网络浏览器 Activity 应始终在其自己的任务中打开(通过在 <activity> 元素中指定 singleTask 启动模式)。这意味着,如果应用发出打开 Android 浏览器的 Intent,则浏览器的 Activity 与应用位于不同的任务中。同时,系统会为浏览器启动新任务,或者如果浏览器已有任务正在后台运行,则会将该任务上移一层以处理新 Intent。

    无论Activity是在新任务中启动,还是在与启动它的Activity相同任务中启动,用户点“返回”都会转到前一个Activity。但是,如果Activity的模式是singleTask,则当后台任务存在该Activity实例时,整个任务都会转移到前台,此时返回栈包含上移到栈顶的所有Activity,如下图。


    image.png

    如需了解有关在清单文件中使用启动模式的详细信息,请参阅 <activity> 元素文档,其中更详细地讨论了 launchMode 属性和可接受的值。

    :使用 launchMode 属性为 Activity 指定的行为可由 Intent 附带的 Activity 启动标志替代,下文将对此进行讨论。

    (2)使用Intent标志

    在启动Activity时,可以通过传递给startActivity的Intent中加入相关的flag,修改Activity与其任务的默认关联方式,比如下面这些flag:

    启动 Activity 时,您可以通过在传递给 startActivity() 的 Intent 中加入相应的标志,修改 Activity 与其任务的默认关联方式。可用于修改默认行为的标志包括:

    FLAG_ACTIVITY_NEW_TASK

    在新任务中启动 Activity。如果已为正在启动的 Activity 运行任务,则该任务会转到前台并恢复其最后状态,同时 Activity 会在 onNewIntent() 中收到新 Intent。这会产生与 "singleTask"launchMode 值相同的行为。

    FLAG_ACTIVITY_SINGLE_TOP

    如果正在启动的 Activity 是当前 Activity(位于返回栈的顶部),则 现有实例会接收对 onNewIntent() 的调用,而不是创建 Activity 的新实例。这会产生与 "singleTop"launchMode 值相同的行为。

    FLAG_ACTIVITY_CLEAR_TOP

    如果正在启动的 Activity 已在当前任务中运行,则会销毁当前任务顶部的所有 Activity,并通过 onNewIntent() 将此 Intent 传递给 Activity 已恢复的实例(现在位于顶部),而不是启动该 Activity 的新实例。

    产生这种行为的 launchMode 属性没有值。

    FLAG_ACTIVITY_CLEAR_TOP 通常与 FLAG_ACTIVITY_NEW_TASK 结合使用。一起使用时,通过这些标志,可以找到其他任务中的现有 Activity,并将其放入可从中响应 Intent 的位置。

    :如果指定 Activity 的启动模式为 "standard",则该 Activity 也会从堆栈中移除,并在其位置启动一个新实例,以便处理传入的 Intent。 这是因为当启动模式为 "standard" 时,将始终为新 Intent 创建新实例。

    TaskAffinity:

    TaskAffinity指示Activity优先属于哪个任务,默认情况下,同一应用的所有Activity具有相同的TaskAffinity,那就是包名,不过我们可以修改TaskAffinity,可以让不同应用的Activity拥有相同的TaskAffinity也可以让同一个应用有不同的TaskAffinity。通过 <activity> 元素的 taskAffinity 属性(是一个字符串值)修改任何给定 Activity 的关联。

    在两种情况下,关联会起作用:

    • 启动 Activity 的 Intent 包含 FLAG_ACTIVITY_NEW_TASK 标志。

      默认情况下,新 Activity 会启动到调用 startActivity() 的 Activity 任务中。它将推入与调用方相同的返回栈。 但是,如果传递给startActivity() 的 Intent 包含 FLAG_ACTIVITY_NEW_TASK 标志,则系统会寻找其他任务来储存新 Activity。这通常是新任务,但未做强制要求。 如果现有任务与新 Activity 具有相同关联,则会将 Activity 启动到该任务中。 否则,将开始新任务。

      如果此标志导致 Activity 开始新任务,且用户按“主页”按钮离开,则必须为用户提供导航回任务的方式。 有些实体(如通知管理器)始终在外部任务中启动 Activity,而从不作为其自身的一部分启动 Activity,因此它们始终将 FLAG_ACTIVITY_NEW_TASK 放入传递给 startActivity() 的 Intent 中。请注意,如果 Activity 能够由可以使用此标志的外部实体调用,则用户可以通过独立方式返回到启动的任务,例如,使用启动器图标(任务的根 Activity 具有 CATEGORY_LAUNCHER Intent 过滤器;请参阅下面的启动任务部分)。

    • Activity 将其 allowTaskReparenting 属性设置为 "true"。

      在这种情况下,Activity 可以从其启动的任务移动到与其具有关联的任务(如果该任务出现在前台)。

      例如,假设将报告所选城市天气状况的 Activity 定义为旅行应用的一部分。 它与同一应用中的其他 Activity 具有相同的关联(默认应用关联),并允许利用此属性重定父级。当您的一个 Activity 启动天气预报 Activity 时,它最初所属的任务与您的 Activity 相同。 但是,当旅行应用的任务出现在前台时,系统会将天气预报 Activity 重新分配给该任务并显示在其中。

    清理Back Stack:

    如果用户长时间离开任务,则系统会清除所有 Activity 的任务,根 Activity 除外。 当用户再次返回到任务时,仅恢复根 Activity。系统这样做的原因是,经过很长一段时间后,用户可能已经放弃之前执行的操作,返回到任务是要开始执行新的操作。

    我们可以使用下列几个 Activity 属性修改此行为:

    • alwaysRetainTaskState
      如果在任务的根 Activity 中将此属性设置为 "true",则不会发生刚才所述的默认行为。即使在很长一段时间后,任务仍将所有 Activity 保留在其堆栈中。

    • clearTaskOnLaunch
      如果在任务的根 Activity 中将此属性设置为 "true",则每当用户离开任务然后返回时,系统都会将堆栈清除到只剩下根 Activity。 换而言之,它与alwaysRetainTaskState 正好相反。 即使只离开任务片刻时间,用户也始终会返回到任务的初始状态。

    • finishOnTaskLaunch
      此属性类似于 clearTaskOnLaunch,但它对单个 Activity 起作用,而非整个任务。 此外,它还有可能会导致任何 Activity 停止,包括根 Activity。 设置为 "true" 时,Activity 仍是任务的一部分,但是仅限于当前会话。如果用户离开然后返回任务,则任务将不复存在。

    相关文章

      网友评论

          本文标题:Task和BackStack

          本文链接:https://www.haomeiwen.com/subject/xkxirctx.html