launchMode

launchMode在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他Activity实例公用一个task里。

task是一个具有栈结构的对象,一个task可以管理多个Activity,启动一个应用,也就创建一个与之对应的task。

Activity一共有以下四种launchMode:

  • standard
  • singleTop
  • singleTask
  • singleInstance

我们可以在AndroidManifest.xml配置<activity>的android:launchMode属性为以上四种之一即可。

standard

standard模式是默认的启动模式,不用为<activity>配置android:launchMode属性即可,当然也可以指定值为standard。
启动模式示例:

1
2
3
4
FirstActivity为默认启动模式

Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
startActivity(intent);

每次intent跳转系统都会在task中生成一个新的FirstActivity实例,并且放于栈结构的顶部,当我们按下后退键时,才能看到原来的FirstActivity实例。

这就是standard启动模式,不管有没有已存在的实例,都生成新的实例。

singleTop

将上面的示例修改FirstActivity启动模式,FirstActivity指定属性android:launchMode=”singleTop”:

1
2
Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
startActivity(intent);

每次intent跳转到同一个FirstActivity实例,如果按一下后退键,程序立即退出,说明当前栈结构中只有一个Activity实例。

1
2
3
4
5
6

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);

Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
startActivity(intent);

先从FirstActivity跳转到SecondActivity,然后SecondActivity再跳转到FirstActivity时,因为此时之前的FirstActivity不在栈顶,此时栈顶是SecondActivity,故从SecondActivity跳转到FirstActivity时新建了一个FirstActivity实例。

intent跳转时系统会先在栈结构中寻找是否有一个FirstActivity实例正位于栈顶,如果有则不再生成新的,而是直接使用;如果没有则创建一个新的实例;如果task里有,但是对应的Activity不是位于栈顶,仍然创建一个新的实例。

singleTask

将上面的示例修改FirstActivity启动模式,FirstActivity指定属性android:launchMode=”singleTask”:

1
2
3
4
5
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);

Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
startActivity(intent);

先从FirstActivity跳转到SecondActivity,然后SecondActivity再跳转到FirstActivity,在这个的过程中,FirstActivity的序列号是不变的,SecondActivity的序列号却不是唯一的,说明从SecondActivity跳转到FirstActivity时,没有生成新的实例,但是从FirstActivity跳转到SecondActivity时生成了新的实例。

从SecondActivity跳转到FirstActivity时,FirstActivity用的之前创建的,同时SecondActivity实例被迫出栈,栈顶只有FirstActivity。

如果将SecondActivity也设置为singleTask模式,那么SecondActivity实例也不是唯一的,因为每次从SecondActivity跳转到FirstActivity时,SecondActivity实例都被迫出栈,下次等FirstActivity跳转到SecondActivity时,找不到存在的SecondActivity实例,于是必须生成新的实例。但是如果我们有ThirdActivity,让SecondActivity和ThirdActivity互相跳转,那么SecondActivity实例就可以保证唯一。

这就是singleTask模式,如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前。

launchMode为singleTask的时候,通过Intent启到一个Activity,如果系统已经存在一个实例,系统就会将请求发送到这个实例上,但这个时候,系统就不会再调用通常情况下我们处理请求数据的onCreate方法,而是调用onNewIntent方法

不要忘记,系统可能会随时杀掉后台运行的Activity,如果这一切发生,那么系统就会调用onCreate方法,而不调用onNewIntent方法,一个好的解决方法就是在onCreate和onNewIntent方法中调用同一个处理数据的方法

singleInstance

这种启动模式比较特殊,因为它会启用一个新的栈结构,将Acitvity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。

将FirstActivity启动模式设置为android:launchMode=”standard”:
将SecondActivity启动模式设置为android:launchMode=”singleInstance”:

1
2
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);

从FirstActivity跳转到SecondActivity时,重新启用了一个新的栈结构,来放置SecondActivity实例,然后按下后退键,就再次回到原始栈结构。

1
2
3
4
5
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);

Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
startActivity(intent);

在SecondActivity中再次跳转到FirstActivity,这个时候系统会在原始栈结构中新生成一个FirstActivity实例,此时在原始栈中有2个FirstActivity实例。

然后按下后退键,从第2个FirstActivity实例回退到第1个FirstActivity实例,再按下后退键时,程序并不退出,而是回到SecondActivity。因为从SecondActivity跳转到FirstActivity的时候,我们的起点变成了SecondActivity实例所在的栈结构,这样一来,我们需要“回归”到这个栈结构。

将FirstActivity启动模式设置为singleTop、singleTask、singleInstance中的任意一个,
将SecondActivity启动模式设置为android:launchMode=”singleInstance”:

1
2
3
4
5
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);

Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
startActivity(intent);

从FirstActivity跳转到SecondActivity时,重新启用了一个新的栈结构,来放置SecondActivity实例,在SecondActivity中再次跳转到FirstActivity时跳转到原来的FirstActivity实例,然后按下后退键时,回到SecondActivity。

文章整理自
基础总结篇之二:Activity的四种launchMode