前言
如何才能开始一个新的Task?
Intent中定义了一个标志FLAG_ACTIVITY_NEW_TASK,在startActivity的Intent参数中加入该标志就能开启一个新的Task。但是,如果系统中已经有相同affinity的Task存在,这时候就不会再启动一个Task,而是将旧的Task带到前台。
Affinity的意思是“亲和度”、“密切关系”,它的类型是字符串,我们可以把它理解成Task的名称。Affinity字串在系统中是唯一的,AMS查找一个Task,最优先比较它的affinity。
ActivityStack类中用来查找Task的方法是findTaskLocked()
findTaskLocked
ActivityRecord findTaskLocked(ActivityRecord target) {
......
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; -
-taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
......
if (!isDocument && !taskIsDocument && task.rootAffinity
!= null) {
if (task.rootAffinity.equals(target.taskAffinity)) {
return r;
}
} else if (taskIntent != null && taskIntent.getComponen
t() != null &&
taskIntent.getComponent().compareTo(cls) == 0
&&
Objects.equals(documentData, taskDocumentData))
{
return r;
} else if (affinityIntent != null && affinityIntent.get
Component() != null &&
affinityIntent.getComponent().compareTo(cls) ==
0 &&
Objects.equals(documentData, taskDocumentData))
{
return r;
}
}
return null;
}
findTaskLocked()方法首先遍历已有TaskRecord对象的affinity变量是否等于ActivityRecord的taskAffinity变量,如果相同就直接把旧的Task带回前台,而不是new一个新的TaskRecord。
既然一个Task的affinity这么重要,它是在哪里定义的呢?在AndroidManifest.xml文件中:Activity标签的taskAffinity属性:当使用标志FLAG_ACTIVITY_NEW_TASK启动一个Activity时才起作用
Application标签的taskAffinity属性:没有指定activity标签的taskAffinity属性的,将会继承application标签的taskAffinity属性应用的包名packageName:没有指定的情况,默认值通常在开发中,很少应用会自定义一个taskAffinity属性,所以默认就是其包名。因此,在应用中如果启动本应用的另一个Activity,即便intent里添加了FLAG_ACTIVITY_NEW_TASK也不一定会启动一个新的Task,除非这个Activity定义了不同的taskAffinity属性。
Activity对象的复用
启动一个Activity时,如果系统的后台Task已经有一个该Activity的实例存在,那么系统会再创建一个新的Activity实例,还是将已经存在的Activity实例切换到前台呢?
答案是:都有可能。有很多因素可以影响结果,包括Activity的属性值以及Intent中指定的标志。我们先看看Activity的属性launcherMode会有哪些影响:
standard模式:standard模式下的Activity每次启动时都会创建该Activity的实例对象;
同一个Task中可以同时存在该Activity的多个实例;一个Activity的多个实例可以出现在多个Task栈中。
singleTop模式:如果设置为singleTop模式的Activity实例位于Task的栈顶,则不会创建一个新的对象,但是该Activity对象切换到前台时,它的onNewIntent()方法将会被调用,新的intent通过这种方式传递给实例对象。如果Activity不在其Task的栈顶,就和standard模式一样,会创建新的实例对象。
singleTask模式:设置为singleTask模式的Activity具有系统唯一性,只能在系统中创建该Activity的一个实例对象。启动设置为singleTask的Activity时,如果系统中已经存在该Activity的实例,则将其所在的Task排在它前面的Activity都出栈,将该Activity带到栈顶,并调用onNewIntent()方法,将新的intent传递给该实例。如果该Activity在系统中还没有实例对象,就会创建一个该Activity的实例对象,如果该Activity的taskAffinity属性值和当前Task的affinity值相同,它会加入到当前TAsk中,否则,即使启动该Activity的Intent中没有指定FLAG_ACTIVITY_NEW_TASK标志,也会启动新的Task,将Activity置于其中。
singleInstance模式:设置为singleInstance模式的Activity同样具有系统唯一性,系统
中只有该Activity的一个实例对象。同时Activity位于一个单独的Task中,该Task中也只
有一个Activity。
allowTaskReparenting属性:通常情况下,一个Activity创建出来后,会停留在某个
Task中,直到它被销毁。但是如果Activity的allowTaskReparenting属性设置为true,
则该Activity可以在不同的Task之间转移。但是,这个属性只有在启动Activity的Intent中
设置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标志时才起作用。
allowRetainTaskState属性:默认情况下,如果一个Task位于后台的时间太长,系统
会清理该Task中的Activity,除了最初启动的Task的Activity以外,其他的Activity都会被
系统销毁。如果应用希望保留这些Activity,可以将启动Task的Activity的
allowRetainTaskState属性设置为true。
clearTaskOnLaunch属性:前面介绍了,当使用带有标志
FLAG_ACTIVITY_NEW_TASK的Intent启动一个Activity时,如果该Acitivty位于一个
Task中,会将Task整体带到前台,其中Activity保持不变。但是如果该Activity启动的是
Task的根Activity(root Activity),同时该Activity的属性clearTaskOnLaunch设置为
true,那么系统出了将Task带到前台外,还会清除除了root Activity以外的所有
Activity。因此,这个属性的作用相当于每次销毁Task,然后重新开始一个。
finishOnTaskLaunch属性:设置为true,系统将会销毁该Activity,然后重新再启动一
个。
除了FLAG_ACTIVITY_NEW_TASK标志以外,Intent中还定义几个和Activity相关的标志: FLAG_ACTIVITY_CLEAR_TOP:如果启动的Activity已经存在,则把该Activity带到前 台,并把它前面的Activity都出栈。 FLAG_ACTIVITY_BROUGHT_TO_FRONT:如果启动的Activity已经存在,则把该 Activity带到前台,但是不关闭它前面的Activity。 FLAG_ACTIVITY_SINGLE_TOP:如果启动的Activity已经位于Task的栈顶,则不会创 建一个新的Activity,而是把该Activity带到前台。 Android开发——Intent中的各种FLAG
近期评论