平时的开发过程中,我们一般会把MainActivity设置为singleTask或者SingleTop。一般的Activity会默认设置为standard。针对Activity的启动模式和任务栈,我做一个系统的总结。


一、任务栈

1、android的任务栈是一个栈的结构,先进后出,用来存放activity。这个栈又被称为返回栈(back stack)。(相当于ios的UINavigationviewController)。显然只有在栈顶(最后一个进栈的元素)的Activity才能与用户进行交互。

2、一个App中可能不止一个任务栈,一个task的Activity可以来自不同的app,同一个app的Activity也可能不在一个task中


二、启动模式

我们可以在manifest文件中设置元素的属性launchMode 来设置启动模式。
四种启动模式:

1、standard 标准模式

standard是默认的启动模式,即如果不指定launchMode属性,则自动就会使用这种启动模式。这种启动模式表示每次启动该Activity时系统都会为创建一个新的实例,并且总会把它放入到当前的任务当中。声明成这种启动模式的Activity可以被实例化多次,一个任务当中也可以包含多个这种Activity的实例。

2、singleTop 栈顶复用模式

这种启动模式表示,如果要启动的这个Activity在当前任务中已经存在了,并且还处于栈顶的位置,那么系统就不会再去创建一个该Activity的实例,而是调用栈顶Activity的onNewIntent()方法。声明成这种启动模式的Activity也可以被实例化多次,一个任务当中也可以包含多个这种Activity的实例。

3、singleTask 栈内复用模式

如果栈中存在这个Activity的实例就会复用这个Activity,不管它是否位于栈顶,复用时,会将它上面的Activity全部出栈,因为singleTask本身自带clearTop这种功能。并且会回调该实例的onNewIntent()方法。

4、singleInstance 单实例模式 (用的很少,业务开发中很少用到)

该模式具备singleTask模式的所有特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具有全局唯一性。以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。

注意:onNewIntent方法会传入一个新的intent,
所以最好在onNewIntent方法中,重新设置一下intent。
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);
}

另外,如果系统内存比较紧张,
可能会提前把singleTop或者singleTask的Activity给释放掉,
此时不会走onNewIntent,而是onCreate。


三、几个常用的Intent flags

除了使用manifest文件之外,你也可以在调用startActivity()方法的时候,为Intent加入一个flag来改变Activity与任务的关联方式

1、FLAG_ACTIVITY_SINGLE_TOP

在google的官方文档中介绍,它与launchMode="singleTop"具有相同的的行为。事实上确实如此,单独的使用FLAG_ACTIVITY_SINGLE_TOP,就能达到和launchMode="singleTop"一样的效果。
那么被设置为FLAG_ACTIVITY_SINGLE_TOP的activity就会实现栈顶复用。如果进入没有设置为FLAG_ACTIVITY_SINGLE_TOP的同一个activity类,还是会重新创建一个activity实例。

2、FLAG_ACTIVITY_NEW_TASK

在google的官方文档中介绍,它与launchMode="singleTask"具有相同的行为。实际上,并不是完全相同!很少单独使用FLAG_ACTIVITY_NEW_TASK,通常与FLAG_ACTIVITY_CLEAR_TASK或FLAG_ACTIVITY_CLEAR_TOP联合使用。单独使用的场景为:比如通过service或者广播去打开一个Activity时,需要addflag为FLAG_ACTIVITY_NEW_TASK,那么这里的FLAG_ACTIVITY_NEW_TASK的意义就是:需要为启动的这个Activity指定或分配一个任务栈,如果你现在正在启动的activity已经有一个任务在运行,那么这个任务会被带到前台并恢复其最后的状态,并且该activity在onNewIntent()中接收到新的意图。

3、FLAG_ACTIVITY_CLEAR_TOP

FLAG_ACTIVITY_CLEAR_TOP的作用是:清除"包含Activity的task"中位于该Activity实例之上的其他Activity实例。

4、FLAG_ACTIVITY_CLEAR_TASK

如果在通过Context.startActivity()启动activity时为Intent设置了此标识,这个标识将导致:在此activity启动之前,任何与此activity相关联的task都会被清除。也就是说,此activity将变成一个空栈中新的最底端的activity,所有的旧activity都会被finish掉,这个标识仅仅和FLAG_ACTIVITY_NEW_TASK联合起来才能使用。

四、taskAffinity、allowTaskReparenting

1、首先来了解一下 taskAffinity

(1)taskAffinity 是activity的任务栈名称,默认任务栈的名称为包名,并且必须包含。
(2)可以单独指定每一个Activity的taskAffinity属性覆盖默认值。
(3)具有相同taskAffinity属性的activity属于同一个任务。
(4)为一个activity的taskAffinity设置一个空字符串时,表明这个activity不属于任何task。
(5)taskAffinity属性不对 standard 和 singleTop 有任何影响。
(6)taskAffinity必须配合singleTask、Intent.FLAG_ACTIVITY_NEW_TASK、allowTaskReparenting才会生效。

2、allowTaskReparenting 属性

该属性的作用是Activity的迁移,当allowTaskReparenting属性和TaskAffinity配合使用时(一般是多个应用处理),Activity能够从一个任务栈迁移到另外一个任务栈。
这里我就不深入去探索了,暂时很少用到。

五、总结

1、singleTask会销毁目标Activity之上的Activity并复用已经存在的目标Activity(调用onNewIntent)。
而Intent.FLAG_ACTIVITY_CLEAR_TOP会连同目标Activity一起销毁,然后重新创建目标Activity。

2、使用Intent.FLAG_ACTIVITY_CLEAR_TOP + Intent.FLAG_ACTIVITY_SINGLE_TOP时调用了onNewIntent方法,复用了MainActivity,说明他们可以实现和singleTask一样的效果

也就是 FLAG_ACTIVITY_CLEAR_TOP + FLAG_ACTIVITY_SINGLE_TOP = singleTask
或者说 FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TOP + FLAG_ACTIVITY_SINGLE_TOP = singleTask