我们所最常用的组件就是 Activity,Android 系统为了满足各种开发的需要,赋予了 Activity 四种不同的启动模式。虽然大家很可能都从各个地方了解过 Activity 的启动模式,但还是建议大家看看这篇文章,我会尽可能地理清思路,便于大家更好地理解启动模式。
任务栈
对于 Android 而言,只能有一个 Activity 处于 Active 和 Visible 的状态,但我们通常由多个 Activity 的需求,那么如何来调度这些 Activity 呢。根据我们日常的使用习惯,使用栈来保存状态最合适不过了,完美符合了 LIFO 的要求,这个栈就是我们所说的任务栈。一般情况下,每个应用都会有一个默认名为包名的 Activity 任务栈。每个 Activity 都可以通过 Manifest 里面中的 android:taskAffinity 来指定其所依附的任务栈。任务栈的名字取决于栈中最底部的那个 Activity 的 taskAffinity,如果没有指定,那就是包名。值得注意的是,当我们启动一个自定义 taskAffinity 的 Activity 时,并不会立即启动另一个任务栈哦,必须得加上 NEW_TASK 的这个 Flag 才行。

我们在日常的使用情况下,通常是通过桌面跳转到对应的 Activity 的,那么这种情况下,栈是怎么分布的了?是有一个全局的任务栈吗?非也!通过桌面跳转是进入了另一个任务栈,我们所熟知的导航区域(返回、HOME、任务列表)都用于辅助我们切换任务栈。我们看看任务列表的情况,就是下图,它所展示的不是一个一个进程,二是一个一个的任务栈。

-
Android 任务栈又称为 Task,它是一个栈结构,具有后进先出的特性,用于存放我们的 Activity 组件。
-
我们每次打开一个新的 Activity 或者退出当前 Activity 都会在一个称为任务栈的结构中添加或者减少一个 Activity 组件,因此一个任务栈包含了一个 Activity 的集合, Android 系统可以通过 Task 有序地管理每个 Activity,并决定哪个 Activity 与用户进行交互,只有在任务栈栈顶的 Activity 才可以跟用户进行交互。
-
在我们退出应用程序时,必须把所有的任务栈中所有的 Activity 清除出栈时,任务栈才会被销毁。当然任务栈也可以移动到后台, 并且保留了每一个 Activity 的状态. 可以有序的给用户列出它们的任务, 同时也不会丢失 Activity的状态信息。
-
需要注意的是,一个 App 中可能不止一个任务栈,某些特殊情况下,单独一个 Actvity 可以独享一个任务栈。还有一点就是一个 Task 中的 Actvity 可以来自不同的 App,同一个 App 的 Activity 也可能不在一个 Task 中。
Standard
接下来我们看看四种基本的启动模式,首先是标准模式,为了方便记忆,我把这种模式称之为「来者不拒」模式。只要有需求,就会新建一个 Activity 的示例,真是来者不拒呀。
- Activity 可以有多个实例
- 示例可以处于不同的任务栈中
- 一个任务栈可以有多个实例
SingleTop
这种模式也很简单,在启动 Activity 之前,会去查找对应的任务栈,如果在栈顶,就沿用这个 Activity,否则就新建一个实例。SingleTop 的适用场景很多,例如我们的消息列表页面,此时通知栏又收到一条消息的时候,点击通知栏的时候,我们是不希望新建一个 Activity 的实例的。
需要注意的是当 Activity 在栈顶的时候,触发的生命周期函数是 onNewIntent,且需要更新 intent,否则通过 getIntent 得到的还是原来的 intent。

SingleTask
相对复杂的启动模式,当系统中(注意是整个 Android 系统中)存在 Activity 的实例时,会将该 Activity 之上的 Activity 纷纷出栈,并调用目标 Activity 的 onNewIntent 方法,否则新建一个实例。这里需要注意的是,根据文档描述,The system creates a new task and instantiates the activity at the root of the new task,但事实上并不是如此,只有你指定了 taskAffinity 的时候,才会给你创建一个新的任务栈,并将该 Activity 作为 Root 节点。
这里有一个额外比较恶心的地方是,当我们调用 startActivityForResult 的时候,4.x版本.会立刻在上个 Activity 中 onActivityResult 中返回一个为 cancel 的 resultCode.(不管新的activity是否是在新的任务栈中启动) 5.x版本修复了这个问题,不管是否定义了taskAffinity,都会把将要被启动的activity的启动模式忽略, onActivityResult方法会正常回调。
SingleInstance
与 SingleTask 相似,但不同的地方在于 SingleInstance 要求在任务栈中有且只有它一个 Activity。
换句话说,A应用需要启动的MainActivity 是singleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A单独在这个新的任务栈中,如果此时B应用也要激活MainActivity,由于栈内复用的特性,则不会重新创建,而是两个应用共享一个Activity的实例。
我们来想一个复杂的例子,在一个应用类,有三个 Activity,分别是 A,B,C,其中 B 是 SingleInstance 的,而 A 和 C 是标准的。A 启动 B 后,B 再启动 C,此时点击返回,会回到哪个界面呢?答案是 A,因为 B 是独立的栈,而 C 在分配的时候,会进入到默认的栈中去,此时默认的栈中是 A 与 C,点击返回的话,就将 C 弹出,此时就显示 A 啦。