Activity的启动模式

来源:互联网 发布:考辛斯体测数据 编辑:程序博客网 时间:2024/05/29 07:06

启动模式概述

我们知道android中是通过任务和返回返回栈来管理Activity,Android 管理任务和返回栈的方式是将所有连续启动的 Activity 放入同一任务和“后进先出”堆栈中。启动模式的作用是用来指定启动的 Activity 的新实例如何与当前任务关联,这句话可能有点抽象,后面会举例详细介绍启动模式的作用


Activity与任务栈关联性

在介绍启动模式之前,我们先来了解一下activity的taskAffinity 属性,该属性指示 Activity 优先属于哪个任务栈,也可以理解为Activity需要的任务栈,taskAffinity 属性取字符串值,默认情况下,Activity的关联任务栈名字为应用包名,在两种情况下,关联会起作用:以singleTask启动模式或者启动 Activity 的 Intent 包含 FLAG_ACTIVITY_NEW_TASK 标志时,待启动的Activity会运行在与名字和TaskAffinity相同的任务栈中,该点后面会详细介绍,第二种情况,Activity 将其 allowTaskReparenting 属性设置为 “true”。在这种情况下,Activity 可以从其启动的任务移动到与其具有关联的任务(如果该任务出现在前台)。如A启动了B的一个Activity,该activity的allowTaskReparenting 属性设置为 “true”,那么B被启动后,Activity会从A的任务栈转移到B的任务栈


启动模式的定义

您可以通过两种方法定义不同的启动模式:
1. 使用清单文件
在清单文件中声明 Activity 时,您可以通过定义android:launchMode该属性值来
指定 Activity 在启动时应该如何与任务关联。
2. 使用 Intent 标志
调用 startActivity() 时,可以在 Intent 中加入一个标志,用于声明新 Activity 如何(或是否)与当前任务关联。

注意:
1. 当上面两种模式都定义时:则使用Intent标志启动模式优先级要高于使用清单文件定义的
2. 某些适用于清单文件的启动模式不可用作 Intent 标志,同样,某些可用作 Intent 标志的启动模式无法在清单文件中定义的


使用清单文件

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

“standard”(默认模式)

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

standard模式

注:该模式下,taskAffinity属性无效
如果以ApplicationContext去启动standard的activity就会报错,这是因为standard的activity默认会进入启动他的Activity所属的栈中,而非Activity的Context并没有所谓的任务栈

“singleTop”

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

栈顶复用模式

注:
1. 为某个 Activity 创建新实例时,用户可以按“返回”按钮返回到前一个 Activity。 但是,当 Activity 的 现有实例处理新 Intent 时,则在新 Intent 到达 onNewIntent() 之前,用户无法按“返回”按钮返回到 Activity 的状态。
2. 如果栈顶不存在该Activity的实例,则情况与standard模式相同。
3. 栈顶复用时,不会再走onCreate,onStart,而是调用onNewIntent(),然后调用onResume
3. 该模式下,taskAffinity属性无效

“singleTask”

栈内复用模式:该模式下,如果 Activity 的一个实例已存在于一个单独的任务中,则多次启动此Activity,系统会通过调用现有实例的onNewIntent() 方法向其传送 Intent,而不是创建新实例。一次只能存在 Activity 的一个实例。具体一点:当一个具有singleTask模式的Activity请求启动后,如Activity A,系统首先查找该Activity 的关联任务栈是否存在,也就是查看该Activity的属性taskAffinity指定的任务栈是否存在,如果任务不存在,就重新创建一个任务栈,然后创建A的实例并放入任务栈中。如果存在A的关联任务栈,就查看该任务栈中是否有A的实例,如果有实例存在,就把该实例调到栈顶,由于singleTask模式默认具有clearTop的效果,所以栈内在A之上的Activity会全部出栈,把A置于栈顶,然后调用A的onNewIntent方法;如果A的实例不存在,就创建A的实例,并把其压入栈中。

栈内复用模式

注:
1. 尽管 Activity 在新任务中启动,但是用户按“返回”按钮仍会返回到前一个 Activity。
2. 栈内复用时,不会再走onCreate,而是调用onNewIntent。 该模式下,会先确认taskAffinity属性再确定具体的使用。
3.不会销毁自身。

“singleInstance”.

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

全局单例模式

注:唯一的任务栈、栈内唯一的Activity 界面启动时,UI表现与其他模式有明显区别。


使用 Intent 标志

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

FLAG_ACTIVITY_NEW_TASK

正如前文所述,这会产生与 “singleTask”launchMode 值相同的行为。唯一不同的是,该模式不具有clearTop效果,即如果该Activity优先所属的任务栈中已经有Activity的实例,在此实例之上的Activity不会出栈,只是将此Activity的实例调到栈顶

FLAG_ACTIVITY_SINGLE_TOP

正如前文所述,这会产生与 “singleTop”launchMode 值相同的行为。

FLAG_ACTIVITY_CLEAR_TOP

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

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

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

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

具有该标记的Activity不出现在最近任务中,等同于在XML中设置android:excludeFromRecents=“true”