Activity启动模式解析
主要内容
Activity是android的四大组件之一,可以说是我们android开发中最常用的技术之一。有关activity的知识点非常多,本文要介绍的是activity的四大启动模式。四大启动模式分别是standard(这是我们最常用的也是默认的一种启动方式)、singleTop、singleTask、singleInstance。接下来我们将分别介绍这四大启动模式以及他们的应用场景。
�任务和返回栈
在学习启动模式之前,我们需要先了解一下任务和返回栈的知识,应用通常包含多个Activity。每个 Activity 均应围绕用户可以执行的特定操作设计,并且能够启动其他 Activity。
任务是指在执行特定作业时与用户交互的一系列 Activity。 这些 Activity 按照各自的打开顺序排列在堆栈(即“返回栈”)中。
设备主屏幕是大多数任务的起点。当用户触摸应用启动器中的图标(或主屏幕上的快捷键)时,该应用的任务将出现在前台。 如果应用不存在任务(应用最近未曾使用),则会创建一个新任务,并且该应用的“主”Activity 将作为堆栈中的根 Activity 打开。
当前 Activity 启动另一个 Activity 时,该新 Activity 会被推送到堆栈顶部,成为焦点所在。 前一个 Activity 仍保留在堆栈中,但是处于停止状态。�这个保存Activity的堆栈就是返回栈。了解了任务以及返回栈以后,我们就可以来正式学习启动模式了。
standard
standard是系统默认的启动模式,系统在启动 Activity 的任务中创建 Activity 的新实例并向其传送 Intent。Activity 可以多次实例化,而每个实例均可属于不同的任务,并且一个任务可以拥有多个实例。返回栈以“后进先出”对象结构运行,下图就是standard模式下返回栈的工作过程。
这里写图片描述
图 1. 显示任务中的每个新 Activity 如何向返回栈添加项目。 用户按“返回”按钮时,当前 Activity 随即被销毁,而前一个 Activity 恢复执行。
在没有特殊要求的大多数情况下,我们均使用这种默认的启动模式。
singleTop
如果当前任务的顶部已存在 Activity 的一个实例,则系统会通过调用该实例的 onNewIntent() 方法向其传送 Intent,而不是创建 Activity 的新实例(官方文档的描述)。这句话的意思就是当一个Activity处于栈顶且启动模式被设置为singleTop时,当再次启动activity就会通过onNewIntent()来启动它,在栈顶不会创建新的实例。
例如在默认情况下返回栈中依次有A-B-C-D四个activity,如果D的启动模式为Standard,当再次启动D时,任务栈中就会变为A-B-C-D-D。但是如果D的启动模式为singleTop,则当再次启动D时,返回栈还是A-B-C-D。如果B的启动模式为singleTop,当再次启动B时,仍然会重新创建B的实例,返回栈变为A-B-C-D-B.
这里写图片描述
这里ABCD的启动模式均为standard,所以当D再次启动D时会重新创建D的实例,回退时的顺序为D-D-C-B-A.
这里写图片描述
这里将D的启动模式设置为singletop,所以当D再次启动D时由于此时位于栈顶的就是D所以不会产生D的实例了,回退时的顺序就是D-C-B-A
这里写图片描述
这里将B设置为了singletop,其他均为standard,点击D时启动了B,由于B并不在栈顶,所以重新创建了B实例,回退时的顺序就是B-D-C-B-A.
singleTask
这是四大启动模式中最难理解的一中了,系统创建新任务并实例化位于新任务底部的 Activity。但是,如果该 Activity 的一个实例已存在于一个单独的任务中,则系统会通过调用现有实例的 onNewIntent() 方法向其传送 Intent,而不是创建新实例。(这是官方文档上的描述,我觉得描述的太抽象很难理解)。
要想彻底理解singleTask这个启动模式,需要先理解一个taskAffinity。每个Activity都有taskAffinity属性,这个属性指出了它希望进入的Task(任务)。如果一个Activity没有显式的指明该 Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果 Application也没有指明,那么该taskAffinity的值就等于包名。而Task也有自己的affinity属性,它的值等于它的根 Activity的taskAffinity的值。
现在就可以来解释一下singleTask这个启动模式了。当一个activity的启动模式为singleTask,当要启动这个activity时,首先会寻找有没有和它taskAffinity相同的任务,如果没有,就会单独创建一个以这个activity的taskAffinity为taskAffinity的任务栈,activity进入到这个新创建的任务栈中;如果有这个任务栈,还会继续寻找在这个任务栈中有没有它的实例存在,如不存在,此activity放入栈顶,如存在,则将此activity上面的所有activity弹出栈外,activity位于此返回栈的栈顶,在此过程中并未创建新的activity实例。
例如,有一个taskAffinity为1的task中存在A-B-C-D四个activity实例,当有B的taskAffinity为1且启动模式为singleTask,此时启动B时并不会启动新的实例,taskAffinity为1的task会变为A-B。如一个Activit E的taskAffinity为2且启动模式为singleTask,则会产生一个新的taskAffinity为2的task,它的栈内只有一个E,而taskAffinity为1的task中亦然是A-B-C-D。
这里写图片描述
这里将B的启动模式设置为了singletask且taskAffinity未重新设置,当D启动B时,由于之前A-B-C-D这个返回栈中已经存在了B,所以B不会创建新的实例而是将C、D挤出返回栈,B通过onNewIntent()至于栈顶,所以回退时的顺序就是B-A.
singleInstance
这种启动模式也比较好理解,当一个activity以这个启动模式启动时,都会为它单独创建一个任务栈,且这个任务栈中有且只能有一个它。
NOTE
无论 Activity 是在新任务中启动,还是在与启动 Activity 相同的任务中启动,用户按“返回”按钮始终会转到前一个 Activity。 但是,如果启动指定 singleTask 启动模式的 Activity,则当某后台任务中存在该 Activity 的实例时,整个任务都会转移到前台。此时,返回栈包括上移到堆栈顶部的任务中的所有 Activity。 下图显示了这种情况。
这里写图片描述
图 :显示如何将启动模式为“singleTask”的 Activity 添加到返回栈。 如果 Activity 已经是某个拥有自己的返回栈的后台任务的一部分,则整个返回栈也会上移到当前任务的顶部。
这里写图片描述
如图,首先打开了bootmode1,点击了AA,假设产生了一个taskAffinity为bootmode1返回栈,其结构是AA-BB,点击home键将其放入后台后打开BootMode,依次点击A-B-C-D,其中D按钮的点击效果是使用隐式启动打开bootmode1里的BB,然后一直按返回键,我们可以看到返回的顺序为BB-AA-D-C-B-A,符合上面的结论.
intent的标记
FLAG_ACTIVITY_NEW_TASK
在新任务中启动 Activity。如果已为正在启动的 Activity 运行任务,则该任务会转到前台并恢复其最后状态,同时 Activity 会在 onNewIntent() 中收到新 Intent。这种启动标记的作用相当于启动模式中的singleTask。
FLAG_ACTIVITY_SINGLE_TOP
如果正在启动的 Activity 是当前 Activity(位于返回栈的顶部),则 现有实例会接收对 onNewIntent() 的调用,而不是创建 Activity 的新实例。这种启动标记的作用相当于启动模式中的singleTop。
FLAG_ACTIVITY_CLEAR_TOP
如果正在启动的 Activity 已在当前任务中运行,则会销毁当前任务顶部的所有 Activity,并通过 onNewIntent() 将此 Intent 传递给 Activity 已恢复的实例(现在位于顶部),而不是启动该 Activity 的新实例。而这个标记通常与FLAG_ACTIVITY_NEW_TASK在一起结合使用。