在Android四大组件之Activity(二)中提到了Task,今天就来认识认识它吧!
1、任务和返回栈
一个Android应用包含多个Activity。每个Activity都应该围绕用户可以执行的特定操作设计,并且能够启动其他的Activity。而且一个Activity甚至是可以启动同一设备上其他Android应用程序的Activity。
任务就是指在执行特定作业时与用户交互的一系列Activity。这些Activity按照各自的开启顺序排列在堆栈中(即返回栈)。
Android设备的主屏幕是大多数任务的起点,当我们触摸应用启动器中的图标时,该应用的任务就会出现在前台。如果应用不存在任务,则会创建一个新的任务,并且该应用的“主”Activity将作为堆栈中的根Activity打开。
当前的Activity启动另一个Activity的时候,新的Activity会被推送到堆栈顶部,成为焦点所在。之前的那个Activity仍然保留在堆栈中,知识处于停止状态。Activity停止时,系统会保持其用户界面的当前状态。当用户按“返回键”的时候,当前Activity将会从堆栈顶部弹出(即Activity被销毁),从而使得前一个Activity恢复执行。堆栈中的Activity永远不会重新排列,只会推入和弹出堆栈。因此,返回栈是以“后进先出”的结构运行的。
任务是一个有机整体,当用户开始新任务或通过“HOME”按钮回到主屏幕的时候,可以移动至“后台”。当另一个任务发生的时候,当前任务仅仅是失去焦点而已。
注意:
后台可以同时运行多个任务。但是,如果用户同时运行多个后台任务的时候,则可能造成系统开始销毁后台的Activity,以回收内存资源,从而导致Activity状态的丢失。
Activity和任务的默认行为总结如下:
1>当 Activity A 启动 Activity B 时,Activity A 将会停止,但系统会保留其状态。如果用户在处于 Activity B 时按“返回”按钮,则 Activity A 将恢复其状态,继续执行。
2> 用户通过按“HOME”按钮离开任务时,当前 Activity 将停止且其任务会进入后台。 系统将保留任务中每个 Activity 的状态。如果用户稍后通过选择开始任务的启动器图标来恢复任务,则任务将出现在前台并恢复执行堆栈顶部的 Activity。
3>如果用户按“返回”按钮,则当前 Activity 会从堆栈弹出并被销毁。 堆栈中的前一个 Activity 恢复执行。销毁 Activity 时,系统不会保留该 Activity 的状态。
4>即使来自其他任务,Activity也可以多次实例化。
2、如何管理任务?
Android 管理任务和返回栈的方式(将所有连续启动的 Activity 放入同一任务和“后进先出”堆栈中)非常适用于大多数应用,而且不必担心 Activity 如何与任务关联或者如何存在于返回栈中。 但是,您可能会决定要中断正常行为。因此你可以通过使用 清单文件元素中的属性和传递给 startActivity() 的 Intent 中的标志来达到你所期望的操作。
可以使用的主要的属性有以下几种:
1>taskAffinity:
与Activity有着亲和关系的任务。从概念上讲,具有相同亲和关系的Activity归属同一任务(从用户的角度,则是归属同一“应用”)。任务的亲和关系由其根Activity的亲和关系确定。
亲和关系确定两件事:Activity更改到父项任务和通过FLAG_ACTIVITY_NEW_TASK标志启动Activity时将用来容纳它的任务。
默认情况下,应用中的所有Activity都具有相同的亲和关系。可以设置该属性来以不同的方式组合他们,甚至可以将在不同应用中定义的Activity置于同一任务内。要指定Activity与任何任务均无亲和关 系,将其设置为空字符串。
如果未设置该属性,则Activity继承为应用设置的亲和关系。应用默认亲和关系的名称是元素设置的软件包名称。
2>launchMode:
这个属性应该比较熟悉吧,就是之前说到的Activity的四种启动模式。主要分为两大类:“standard”和“singleTop”为一类;“singleTask”和“singleInstance”为另一类。
用“standard”或“singleTop”启动模式的 Activity 可多次实例化。 实例可归属任何任务,并且可以位于 Activity 堆栈中的任何位置。 它们通常启动到名为 startActivity() 的任务之中。
用“singleTask”和“singleInstance”启动模式的Activity 只能启动任务。 它们始终位于 Activity 堆栈的根位置。此外,设备一次只能保留一个 Activity 实例(只允许一个此类任务 ) 。
四种启动模式的简单对比:
3>allowTaskReparenting:
当启动Activity的任务接下来转到前台时,Activity是否能从该任务转移到与其有亲和关系的任务(“true”表示它可以转移,“false”表示它仍须留在启动它的任务处)。默认值“false”。
4>clearTaskOnLaunch:
是否每当从主屏幕重新启动任务时都从中移除根Activity之外的所有Activity(“true”表示始终将任务清除到只剩其根Activity;“fasle”表示不做清除。默认值为“fasle”).
该属性只对启动新任务的Activity(根Activity)有意义,对于任务中的所有其他Activity。均忽略该属性。
如果该属性和 allowTaskReparenting 的值均为“true”,则如上所述,任何可以更改父项的 Activity 都将转移到与其有亲和关系的任务;其余 Activity 随即被移除。
5>alwaysRetainTaskState:
系统是否始终保持Activity所在任务的状态(“true”表示保持,即无论用户如何到达任务,将始终返回到最后状态的任务。,“false”表示允许系统在特定情况下将任务重置到其初始状态。默认值为“false”。)
该属性只对任务的根Activity有意义;对于所有其他Activity,均忽略该属性。
6>finishOnTaskLaunch:
每当用户再次启动其任务时,是否关闭现有Activity实例(“true”表示应关闭,“false”表示不应关闭,默认值“false”)。
如果该属性和 allowTaskReparenting 均为“true”,则优先使用该属性。 Activity 的亲和关系会被忽略。 系统不是更改 Activity 的父项,而是将其销毁。
可以使用的主要Intent标志包括(详细介绍会在Intent中在做介绍):
1>-FLAG_ACTIVITY_NEW_TASK:
在新任务中启动Activity。如果已为正在启动的Activity运行任务。则该任务会转到前台并恢复其最后状态,同时Activity会在onNewIntent()中收到新Intent。(产生与“singleTask”launchMode值相同的行为)。
2>- FLAG_ACTIVITY_CLEAR_TOP:
如果正在启动的Activity已在当前任务中运行,则会销毁当前任务顶部的所有Activity,并通过onNewIntent()将此Intent传递给Activity已恢复的实例,而不是启动该Activity的新实例。
3>- FLAG_ACTIVITY_SINGLE_TOP:
如果Activity是当前Activity(位于返回栈的顶部),则现有实例会接收对onNewIntent()的调用,而不是创建Activity的新实例。(产生与“singleTop”launchMode值相同的行为)。
FLAG_ACTIVITY_CLEAR_TOP 通常与 FLAG_ACTIVITY_NEW_TASK 结合使用。一起使用时,通过这些标志,可以找到其他任务中的现有 Activity,并将其放入可从中响应 Intent 的位置。
3、定义启动模式
启动模式允许我们定义Activity的新实力如何与其当前任务关联。
我们可以通过以下两种方法定义不同的启动模式:
1>使用清单文件
在清单文件中声明Activity时,可以使用元素的launchMode属性指定Activity应该如何与任务关联。launchMode 属性指定有关应如何将 Activity 启动到任务中的指令。
注:使用 launchMode 属性为 Activity 指定的行为可由 Intent 附带的 Activity 启动标志替代。
2>使用Intent标志
启动Activity时,我们可以通过传递给startActivity()的Intent中加入相应的标志,修改Activity与其任务的默认关联方式。
4、处理关联
“关联”指示Activity优先属于哪个任务。默认情况下,同一个应用中的所有Activity彼此关联。因此,在默认的情况下,同一个应用中的所有Activity优先位于相同任务中。
可以对Activity的默认关联进行修改。在不同应用中定义的Activity可以共享关联,或者可为在同一个应用中定义的Activity分配不同的任务关联。
可以通过使用元素的taskAffinity属性修改任何给定Activity的关联,这个属性取字符串值,该值必须不同于在元素中声明的默认软件包名称,因为系统使用该名称标识应用的默认任务关联。
下面两种情况,关联会起作用:
1>启动Activity的Intent含 FLAG_ACTIVITY_NEW_TASK 标志。
2>Activity 将其 allowTaskReparenting 属性设置为 "true"。
注意:
如果从用户的角度来看,一个.apk文件包含多个“应用”,则您可能需要使用taskAffinity属性将不同关联分配给每个“应用”相关的Activity。
5、清理返回栈
如果用户长时间离开任务,则系统会清除所有Activity的任务,根Activity除外。当用户再次返回到任务时,仅恢复根Activity。
可以使用下面几个属性修改Activity的行为:
1>alwaysRetainTaskState
如果在任务的根Activity中将此属性设置为“true”,则不会发生刚才所述的默认行为。即使很长一段时间后,任务仍将所有Activity保留在其堆栈中。
2>clearTaskOnLaunch
如果在任务的根Activity中将此属性设置为“true”,则每当用户离开任务然后返回时,系统都会将堆栈清除到只剩下根Activity。(这个属性与alwaysRetainTaskState正好相反。)即使只离开任务片刻时间,用户也始终会返回到任务的初始状态。
3>finishOnTaskLaunch
这个属性类似于clearTaskOnLaunch,但它对单个Activity起作用,而非整个任务。这个属性可能会导致任何Activity停止(包括根Activity)。
当这个属性设置为“true”时,Activity仍是任务的一部分,但是仅限于当前会话。如果用户离开然后再返回任务,这个任务就不存在了。
6、启动任务
通过为 Activity 提供一个以 "android.intent.action.MAIN" 为指定操作、以 "android.intent.category.LAUNCHER" 为指定类别的 Intent 过滤器,我们可以将 Activity 设置为任务的入口点。
例如:
android:name=".extra.WelcomeActivity"
android:screenOrientation="portrait"
>
此类 Intent 过滤器会使 Activity 的图标和标签显示在应用启动器中,让用户能够启动 Activity 并在启动之后随时返回到创建的任务中。
第二个功能非常重要:用户必须能够在离开任务后,再使用此Activity启动器返回该任务。
只有在Activity具有ACTION_MAIN和CATEGORY_LAUNCHER过滤器时,才应该使用将Activity标记为“始终启动任务”的两种启动模式。(即“singleTask”和“singleInstance”)
7、概览屏幕
概览屏幕是一个系统级别的UI,在其中列出了最近访问过的Activity和任务。用户可以浏览该列表并选择要恢复的任务,也可以通过滑动清除任务将其从列表中移除。
通常,我们应该允许系统定义任务和Activity在概览屏幕中的显示方法,并且无需修改此行为。不过,应用可以确定Activity在概览屏幕中的显示方式和时间。
8、将任务添加到概览屏幕
通过使用 Intent 类的标志添加任务,您可以更好地控制某文档在概览屏幕中打开或重新打开的时间和方式。 使用 属性时,您可以选择始终在新任务中打开文档,或选择对文档重复使用现有任务。
9、使用Intent标志添加任务
为Activity创建新文档时,可调用Activity.AppTask类的startActivity()方法。以向其传递启动Activity的Intent。要插入逻辑换行符以便系统将Activity视为新任务显示在概览屏幕中,可在启动Activity的Intent的addFlags()方法中传递FLAG_ACTIVITY_NEW_DOCUMENT标志。
(注意:FLAG_ACTIVITY_NEW_DOCUMENT 标志取代了 FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 标志,后者自 Android 5.0(API 级别 21)起已弃用。
如果在创建新文档时设置 FLAG_ACTIVITY_MULTIPLE_TASK 标志,则系统始终会以目标 Activity 作为根创建新任务。此设置允许同一文档在多个任务中打开。
(注意:使用 FLAG_ACTIVITY_NEW_DOCUMENT 标志启动的 Activity 必须具有在清单文件中设置的 android:launchMode="standard" 属性值(默认)。
当主 Activity 启动新 Activity 时,系统会搜遍现有任务,看看是否有任务的 Intent 与 Activity 的 Intent 组件名称和 Intent 数据相匹配。 如果未找到任务或者 Intent 包含 FLAG_ACTIVITY_MULTIPLE_TASK 标志,则会以该 Activity 作为其根创建新任务。如果找到的话,则会将该任务转到前台并将新 Intent 传递给 onNewIntent()。新 Activity 将获得 Intent 并在概览屏幕中创建新文档,如下例所示:
10、使用Activity属性添加任务
此外,Activity 还可以在其清单文件中指定始终通过使用 属性 android:documentLaunchMode 进入新任务。 此属性有四个值,会在用户使用该应用打开文档时产生以下效果:
1>intoExisting
该Activity会对文档重复使用现有任务。(这与不设置 FLAG_ACTIVITY_MULTIPLE_TASK 标志、但设置 FLAG_ACTIVITY_NEW_DOCUMENT 标志所产生的效果相同。)
2>always
该Activity为文档创建新任务,即便文档已打开也是如此。(使用此值与同时设置 FLAG_ACTIVITY_NEW_DOCUMENT 和 FLAG_ACTIVITY_MULTIPLE_TASK标志所产生的效果相同。)
3>none
该Activity不会为文档创建新任务。概览屏幕将按其默认方式对待此 Activity:为应用显示单个任务,该任务将从用户上次调用的任意 Activity 开始继续执行。
4>never
该Activity不会为文档创新新任务。设置此值会替代 FLAG_ACTIVITY_NEW_DOCUMENT 和 FLAG_ACTIVITY_MULTIPLE_TASK 标志的行为,并且概览屏幕将为应用显示单个任务,该任务将从用户上次调用的任意 Activity 开始继续执行。
注意:对于除 none 和 never 以外的值,必须使用 launchMode="standard" 定义 Activity。如果未指定此属性,则使用 documentLaunchMode="none"。
11、移除任务
在默认情况下,在Activity结束后,文档任务会从概览屏幕中自动移除。我们可以使用ActivityManager.AppTask 类、Intent 标志或 属性替代此行为。
例如:
1>将 属性 android:excludeFromRecents 设置为 true,可以始终将任务从概览屏幕中完全排除。
2>将 属性 android:maxRecents 设置为整型值,设置应用能够包括在概览屏幕中的最大任务数。默认值为 16。(达到最大任务数后,最近最少使用的任务将从概览屏幕中移除。 最大值为 50(内存不足的设备上为 25);小于 1 的值无效。)
12、使用AppTask类移除任务
在概览屏幕创建新任务的Activity中,我们可以通过 finishAndRemoveTask() 方法指定何时移除该任务以及结束所有与之相关的 Activity。
public void onRemoveFromRecents(View view) {
// The document is no longer needed; remove its task.
finishAndRemoveTask();
}
13、保留已完成的任务
如果要将任务保留在概览屏幕中。可以启动Activity的Intent的addFlags()方法中传递FLAG_ACTIVITY_RETAIN_IN_RECENTS 标志。
要达到同样的效果,可以将 属性 android:autoRemoveFromRecents 设置为 false。
文档 Activity 的默认值为 true,常规 Activity 的默认值为 false。
欢迎大家关注我的微信公众号!!!
网友评论