假设当前有一个任务TaskA,在它的回退栈中有三个Activity,其他两个在当前的Activity的下面。当用户按下主屏幕按钮时开启一个新的应用程序。当新的应用程序的主界面出现的时候,TaskA就会到后台。而新的应用程序在启动的时候就会开启一个自己的拥有自身Activity的栈的Task。用户和这个新的应用程序交互以后,按下主屏幕的按钮回到主屏幕并且选择Task的任务图标点击运行。现在,TaskA回到了前台——它所属的回退栈中的三个Activtiy都是有效地并且栈顶的Activtiy恢复到以前的状态。同理,在这个时候你也可以点击主屏幕的按钮选择TaskB。这是一个android的多任务的例子。注意:Android允许多个任务运行在后台。但是如果用户一次性运行在后台的任务太多,系统可能会因为要回收内存而销毁在后台的activity,这也就造成了activity状态的丢失。
基于以上原因,虽然android系统默认在activity停止的时候就会保存状态,但是我们依旧应该调用activity的onSaveInstanceStatus回调方法保存activity的状态,以避免acitvitiy被销毁和重建。
因为在回退栈中的Activity并不会提前计算好的,如果我们的应用程序允许在不止一个activity中打开一个特殊的activity,那么每一次就会实例化一个新的activity实例并且压入到栈中(而不是把之前实例化好的activity带回到栈顶部)。如此一来,一个activity可能被实例化多次,如下图:
这因为如此,当用户点击回退按钮时,这个activity的每一个实例都会按照被打开的顺序重现。然而如果我们不想要一个activity实例多次,那么我们可以修改这个默认行为,以下我么来学习如何管理Tasks。
但是在学习之前,我们首先需要总结一下Android对于Activity和Task有哪些默认行为:
1、当Activity A开启Activity B时,Activity A 就会停止,但是系统会保存它的状态,当用户在ActivtiyB点击回退按钮时,ActivityA就会恢复保存的状态。
2、当用户点击回退按钮离开一个Task的时候,当前的activity就会停止并且,它所在的Task也会回到后台,系统会保存回退栈中的每一个activity的状态。如果用户将来选择了开启这个任务的图标,使得这个任务恢复,这个就会回到前台并且恢复这个回退栈中顶部的Activity。
3、当用户点击回退按钮时,当前的activity会被从回退栈中弹出并且销毁,而之前的activity就会被恢复。而销毁的activity系统是不会保存它的状态的。
那么,这个时候我们正式开始学习如何管理Task。
正如上面所说的,android管理Task和回退栈是把所有的成功开启的Activity放入到同一个Task和先进后出的回退栈中——这对于大多数应用程序都是起作用的,你不需要担心你的Activity是如何关联到Task和如何存在在回退栈中的。然而,我们可能需要去中断默认行为。例如我们可能需要我们的应用程序的一个activity开启一个新的任务,而不是在当前的Task中,或者我们可能想要当开启一个activity时带出已经存在的实例,而不是创建一个新的实例,或者我们可能想要清空全部的activity除了根Activity,当用户离开这个任务的时候。
我们可以在manifest文件中的activity元素中配置或者在startActivity时封装flag到intent对象中来实现上述的这些功能。
在activity元素标签中我们可以使用以下参数:
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
- 在Intent的flag中可以使用:
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_SINGLE_TOP
- 那么如何定义运行模式呢?
- 运行模式允许我们定义一个activity的实例是如何和当前的Task建立相关性的。我们有两种方式来定义运行模式的。
- 1、在Manifest文件中配置
- 2、使用Intent的flag属性
- 注意:在一些运行模式在mainfest定义是有效地但是在Intent的flag定义可能就是无效的,同理,一些运行模式在Intent的flag运行是有效地,但是在manifest文件中就可能是无效的。
- 在manifest文件中进行运行模式的配置
- 当我们在manifest文件中定义一个activity时,我们可以使用activity元素的launchMode这个属性来配置这个activity是如何和一个Task相关联的。
- 以下是几种我们可以为launchMode配置的运行模式:
- "standard":这个模式是系统默认的。它允许一个activity被实例化多次,每一个activity实例可以属于不同的Task,也可以一个Task包含多个Activity实例。
- "singleTop":如果一个activity的实例已经存在在当前Task的顶部,系统通过调用onNewIntent方法发送这个Intent给这个实例,而不是创建一个新的activity的实例。而其他不是顶部的activity则仍然能够被实例化多次,每一个实例都可以属于多个不同的Task,每一个Task可以有多个实例。例如,假设一个任务的回退栈包含A-B-C-D四个activity,D是在顶部,当一个D类的Intent到达的时候,如果运行模式是默认的standard,则系统会创建一个新的实例D,回退栈中就变为A-B-C-D-D,但是如果运行模式是singleTop,则为A-B-C-D;但是如果一个B类型的到达的时候,则为A-B-C-D-B.
- "singleTask":在一个Task的回退栈中一个activity只能存在一个实例。
"singleInstance"
:和singleTask一样,除了是在一个Task回退栈中只有仅有一个activity.
- 使用Intent的flag进行定义
- 当开启一个activity的时候,我们可以用定义startActivity方法的Intent对象的flag来修改这个activity到这个Task的相关性。
- FLAG_ACTIVITY_NEW_TASK:在一个新的Task中开启一个Activity,如果我们要开启的activity的这个Task已经存在,那么这个Task就会被置于前台并且恢复到被存储的状态。这个activity会接收到这个Intent在onNewIntent()方法中。这个和上面的singleTask同样的意思。
- FLAG_ACTIVITY_SINGLE_TOP:如果被开启的activity是当前的activity即是顶部的activity,那么这个存在的实例调用onNewIntent方法,而不是创建一个activity的新的实例。这个和singleTop的运行模式相同的原理。
- FLAG_ACTIVITY_CLEAR_TOP:如果被开启的activity在正在运行的Task中,那么系统不会重新创建一个实例,相反会销毁在当前回退栈中在它之上的所有activity,通过onNewIntent方法将它置于顶部。
- 清空回退栈
- 如果用户离开了一个Task太久,那么系统会销毁掉这个Task的除了根activity的所有activity,当用户回到这个任务的时候,只能恢复这个根activity。系统这样设计,是因为考虑到当用户离开太久的话,当回来的时候很可能放弃之前做的事情去进行一些新的操作。
- 以下定义了一些属性,我们可以用他们修改默认这个行为:
- alwaysRetainTaskState:如果一个Task的根activity的这个属性被设置为true,那么这个默认的行为不会发生,这个Task甚至在很长一段时间都保留着所有的activity。
- clearTaskOnLaunch:如果一个Task的根activity的这个属性被设置为true,那么无论用户什么时候离开这个Task后重新返回以后,系统会清空掉除了根activity的全部activity。换而言之,它是alwaysRetainTaskState的相反的意思。用户哪怕离开这个Task一会儿,用户总是返回到初始的状态。
- finishOnTaskLaunch:这个属性和clearTaskOnLaunch很相似,但是它仅仅操作一个单独的activity,而不是整个Task。它也清空包括acitiviy的所有的activity。如果这个属性被设置为true,这个activity仅仅保持当前session的Task的部分actvitiy。如果用户离开后返回这些activity将不会呈现。