Activity 任务和返回堆栈
Task是一系列Activity的集合,这些 Activity 按照每个 Activity 打开的顺序排列在一个返回堆栈中。
按照堆栈的“后进先出”数据结构规则
- 在当前 Activity 启动另一个 Activity 时,新的 Activity 将被推送到堆栈顶部并获得焦点。
- 上一个 Activity 仍保留在堆栈中,但会被pause/stop。
- 当 Activity 停止时,系统会保留其界面的当前状态。
- 当用户按返回按钮时,当前 Activity 会从堆栈顶部退出(该 Activity onDestroy),上一个 Activity 会onStart/resume(界面会恢复到上一个状态)。
如何一个task内的activity 都被销毁,那这个task也将不存在
task是一系列Activity的集合,每一个task都是独立整体单元,通常情况下,一个APP只会存在一个Task。在APP退后台后,整个task都会被置于后台,但他的堆栈状态不会发生改变,等再次回到前台的时候,会恢复其原来的状态和顺序。
Android 管理任务和返回堆栈的方式是将所有接连启动的 Activity 放到同一任务和一个“后进先出”堆栈中。但我们在开发过程中,这个简单的规则并不能满足我们,比如一个已经存在栈中的activity,我们再去start他,我们希望可以直接把它推到栈顶复用;在退后台,我们希望可以清空堆栈?又或者我们希望一个app可以有多个task?
这些场景在堆栈管理中,我们都可以借助 <activity> 清单元素中的属性以及您传递给 startActivity()
的 intent 中的标记来实现上述目的。
Activity的启动模式
我们可以通过清单配置配置launchMode 四种模式
或者通过Intent 结合Flag来实现
在新任务中启动 Activity。如果您现在启动的 Activity 已经有任务在运行,则系统会将该任务转到前台并恢复其最后的状态,而 Activity 将在 onNewIntent()
中收到新的 intent。
这与上一节中介绍的 "singleTask"
launchMode 值产生的行为相同。
如果要启动的 Activity 是当前 Activity(即位于返回堆栈顶部的 Activity),则现有实例会收到对 onNewIntent()
的调用,而不会创建 Activity 的新实例。
这与上一节中介绍的 "singleTop"
launchMode 值产生的行为相同。
如果要启动的 Activity 已经在当前任务中运行,则不会启动该 Activity 的新实例,而是会销毁位于它之上的所有其他 Activity,并通过 onNewIntent()
将此 intent 传送给它的已恢复实例(现在位于堆栈顶部)。
launchMode 属性没有可产生此行为的值。
FLAG_ACTIVITY_CLEAR_TOP
最常与 FLAG_ACTIVITY_NEW_TASK
结合使用。将这两个标记结合使用,可以查找其他任务中的现有 Activity,并将其置于能够响应 intent 的位置
四种启动模式
standard(标准模式)
- 不复用Activity,startActivity会启动一个新的Activity实例并且置于栈顶,即使栈内已经有这个Activity实例
- 举例:
当前Activity栈已经存在ABC三个Activity,需要新启动C,则Activity栈变成ABCC,并不会对原来的C进行复用
singleTop(栈顶复用模式)
- 栈顶复用,startActivity启动一个新的Activity时,当前栈顶已经存在这个Activity实例,不会启动新的Actiivty,直接复用当前栈顶Activity,并且回调Activity.onNewIntent方法,如果栈内已有这个Activity但是不在栈顶,则不复用直接启动一个新的Activity实例
- 举例:
1. 当前Activity栈已经存在ABC三个Activity,需要新启动D(singleTop),则Activity栈变成ABCD
2. 当前Activity栈已经存在ABC三个Activity,需要新启动C(singleTop),则Activity栈还是ABC,C被复用并且回调了C的onNewIntent方法
3. 当前Activity栈已经存在ABC三个Activity,需要新启动B(singleTop),则Activity栈变成ABCB,不会对B进行复用
singleTask(栈内复用模式)
- 栈内复用,startActivity启动一个新的Activity时,当前栈内已经存在这个Activity实例,不会启动新的Actiivty,直接复用当前栈内Activity,将这个Activity之上的Activity出栈,并且回调Activity.onNewIntent方法
- 举例:
0. 前提是taskAffinity相同
1. 当前Activity栈已经存在ABC三个activity,需要新启动D(singleTask),则Activity栈变成ABCD
2. 当前Activity栈已经存在ABC三个activity,需要新启动C(singleTask),则Activity栈还是ABC,C被复用并且回调了C的onNewIntent方法
3. 当前Activity栈已经存在ABC三个activity,需要新启动B(singleTask),则Activity栈变成AB,B被复用并且回调了B的onNewIntent方法,C被出栈(也就是执行了onPause,onStop,onDestory生命周期)
singleInstance(单例模式)
- 不复用Activity,startActivity会启动一个新的Activity栈并且启动一个新的Activity实例,也就是一个栈内有且仅有一个Activity实例
- 举例:
当前Activity栈已经存在ABC三个activity,需要新启动D(singleInstance),则新建Activity栈,并将D放入新的Activity栈
亲和性
“亲和性”表示 Activity 倾向于属于哪个任务。默认情况下,同一应用中的所有 Activity 彼此具有亲和性。
使用 <activity> 元素的 taskAffinity 属性修改任何给定 Activity 的亲和性。
- 物以类聚,人以群分,该属性表明Activity之间的相关性
- ApplicationInfo.taskAffinity默认是包名(com.xxx.xxx)
- 当前应用的Activity.taskAffinity默认是ApplicationInfo.taskAffinity
- 该属性主要和SingleTask启动模式(
FLAG_ACTIVITY_NEW_TASK
标记)或者allowTaskReparenting属性配对使用
清除返回堆栈
如果用户离开任务较长时间,系统会清除任务中除根 Activity 以外的所有 Activity。当用户再次返回到该任务时,只有根 Activity 会恢复。系统之所以采取这种行为方式是因为,经过一段时间后,用户可能已经放弃了之前执行的操作,现在返回任务是为了开始某项新的操作。
您可以使用一些 Activity 属性来修改此行为:
如果在任务的根 Activity 中将该属性设为 "true"
,则不会发生上述默认行为。即使经过很长一段时间后,任务仍会在其堆栈中保留所有 Activity。
如果在任务的根 Activity 中将该属性设为 "true"
,那么只要用户离开任务再返回,堆栈就会被清除到只剩根 Activity。也就是说,它与 alwaysRetainTaskState 正好相反。用户始终会返回到任务的初始状态,即便只是短暂离开任务也是如此。
该属性与 clearTaskOnLaunch 类似,但它只会作用于单个 Activity 而非整个任务。它还可导致任何 Activity 消失,包括根 Activity。如果将该属性设为 "true"
,则 Activity 仅在当前会话中归属于任务。如果用户离开任务再返回,则该任务将不再存在。对于那些您不希望用户能够返回到 Activity 的情况,请将 <activity>
元素的 finishOnTaskLaunch 设置为 "true"
实现原理
关键类:ActivityStack,TaskRecord,ActivityRecord,Activity
- ActivityInfo拥有taskAffinity属性,也就是说每个Activity都有taskAffinity属性
- ActivityRecord持有一个ActivityInfo对象,也就是说一个ActivityRecord对应一个Activity
- Task拥有taskAffinity属性,也就是说Task对应一种taskAffinity。同时Task持有一个ActivityRecord列表,也就是说一个Task对应多个ActivityRecord
- ActivityStack继承自Task,与Task具有同样的功能和属性,负责ActivityRecord || Activity栈的状态和管理,一个ActivityStack对应一个Task对应多个ActivityRecord
- RecentTasks持有Task列表,也就是我们常见的最近任务列表
参考:
https://www.jianshu.com/p/4259ed469fd1