前言

当用户多次启动同一个Activity的时候,系统默认会一直为这个Activity创建实例,并将实例放入任务栈中,在用户按back键的时候会一一回退,每按一次任务栈的时候,栈顶的任务就会出栈,当任务栈为空的时候系统会回收这个任务栈。这就是在默认的情况下,系统对于Activity的处理方式。而这种默认的方式在某些时候可能不太符合开发者的意图。所以Android出现了多种的启动模式和标志位来更改这一默认的行为。

Activity的LaunchMode

目前有四种LaunchMode,分别是:standard、singleTop、singleTask以及singleInstance。
为了方便说明和解释,我这里写了一个Demo,以上传到GitHub,详情请点击。界面如下:
{mdFileName}-201837155052
分别对应4种状态的LaunchMode。

standard LaunchMode

标准模式,这是系统默认的模式,每次启动的Activity的时候会默认创建一个实例,不管这个实例是不是存在。被创建的Activity实例符合典型情况下的生命周期。
在这种情况下,谁启动了这个Activity,那么这个Activity就属于启动它的Activity的任务栈中。比如: A启动了B,那么B就属于A的任务栈的成员。

Demo点击第一项按钮4下结果如下:
{mdFileName}-201837123217
可以看到:
这里依次调用了4次的onCreate,且每次的hashcode都不一样。说明分别创建了4次Activity实例。而且任务栈的ID一直都是88.这也就说明了**谁启动Activity,该Activity就位于哪个任务栈中的说法**。

singleTop LaunchMode

栈顶复用模式。在这种模式下,如果新的Activity已经处于任务栈的栈顶,那么这个Activity将不会被创建。同时,它的onNewIntent方法会被回调,通过此方法就可以取出当前请求的信息。但是如果新的Activity不是位于栈顶,那么这个Activity会被实例化。
比如: 一个任务栈中从栈顶到栈底的Activity顺序是:ABCD,如果需要启动任务A,任务A的启动模式为singleTop,那么这个A不会被实例化,而是会调用onNewIntent方法。如果需要启动B,任务B的启动模式为singleTop,那么由于B不在栈顶,那么依然会实例化B,此时任务栈的顺序是:BABCD。

Demo第二项点击4下Log如图所示:
{mdFileName}-201837155237
可以看到:
只第一次点击的时候调用了onCreate方法,之后便是调用的onNewIntent方法。而且hashcode都是一样的。这就说明:**新的Activity如果位于栈顶,那么新的Activity不会被实例化。**

singleTask LaunchMode

栈内复用模式。在这种模式下,只要Activity在任务栈中存在,那么就不会重新创建实例,和singleTop一样,系统会自动回调onNewIntent方法。
比如:当前任务栈中有ABCD四个Activity,需要启动一个Activity C,这个时候任务栈中有Activity C,那么会直接将Activity C调到栈顶,同时回调onNewIntent方法,**由于singleTask具有cleanTop的效果**,所以此时的任务栈的Activity为CD。如果需要启动Activity F,而Activity F不存在,所以会直接实例化Activity F,并压入栈顶。

log截图如下:

{mdFileName}-201837155659

这里的操作步骤是:
点击进入到singleTask界面,此时出现第一个onCreate,然后点击进入到其他Activity,出现第二个onCrete。此时应该注意到,任务栈的栈顶是其他Activity,这个时候在其他Activity点击返回到singTask。由于采用的是singleTask模式,singleTask已经在任务栈中,所以是直接调用,回调onNewIntent。

而且由于cleanTop效果,按返回键的时候,其他Activity是不会再出现的。这一点的话,在BaseActivity.java中重写生命周期的方法就能看出来。

singleInstance LaunchMode

单实例模式。这是一种加强的singleTask模式,具有singleTask的所有特性(cleanTop等),还有一点:使用这种模式的Activity只能单独的位于一个单独的任务栈中。
比如:Activity A是singleInstance模式,当A启动后,系统会单独为这个A创建一个任务栈,由于栈内复用的原因,不会再创建新的Activity A的实例。
{mdFileName}-2018371622
由于这个是单实例模式,对于同一个Activity来说,是直接复用。

总结

TaskAffinity,任务相关性,这个参数标识了一个Activity需要的任务栈的名字,在默认情况下,这个任务栈的名字为应用的包名。任务栈分为前台任务栈和后台任务栈。位于后台任务栈的Activity是处于暂停状态。