Activity的启动模式详解

来源:互联网 发布:软件开发安卓 编辑:程序博客网 时间:2024/05/29 18:37

1、概念

在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作。在Android中Activity的启动模式决定了Activity的启动运行方式。

Activity启动方式有四种,分别是:
standard
singleTop
singleTask
singleInstance

可以根据实际的需求为Activity设置对应的启动模式,从而可以避免创建大量重复的Activity等问题。

2、四种模式

Activity启动模式设置:

    <activity android:name=".MainActivity" android:launchMode="standard" />

Activity的四种启动模式:

1. standard    默认启动模式,每次激活Activity时都会创建Activity,并放入任务栈中。

例如:
若我有一个Activity名为A1, 上面有一个按钮可跳转到A1。那么如果我点击按钮,便会新启一个Activity A1叠在刚才的A1之上,再点击,又会再新启一个在它之上……
点back键会依照栈顺序依次退出。

2. singleTop    如果在任务的栈顶正好存在该Activity的实例, 就重用该实例,    否者就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)。

例如:
若我有两个Activity名为B1,B2,两个Activity内容功能完全相同,都有两个按钮可以跳到B1或者B2,唯一不同的是B1为standard,B2为singleTop。
若我意图打开的顺序为B1->B2->B2,则实际打开的顺序为B1->B2(后一次意图打开B2,实际只调用了前一个的onNewIntent方法)
若我意图打开的顺序为B1->B2->B1->B2,则实际打开的顺序与意图的一致,为B1->B2->B1->B2。

3. singleTask    如果在栈中已经有该Activity的实例,就重用该实例,重用时会让该实例回到栈顶,    因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中。 

例如:
若我的应用程序中有三个Activity,C1,C2,C3,三个Activity可互相启动,其中C2为singleTask模式,那么,无论我在这个程序中如何点击启动,如:C1->C2->C3->C2->C3->C1-C2,C1,C3可能存在多个实例,但是C2只会存在一个,并且这三个Activity都在同一个task里面。
但是C1->C2->C3->C2->C3->C1-C2,这样的操作过程实际应该是如下这样的,因为singleTask会把task中在其之上的其它Activity destory掉。
操作:C1->C2, C1->C2->C3 , C1->C2->C3->C2, C1->C2->C3->C2->C3->C1 ,C1->C2->C3->C2->C3->C1-C2
实际:C1->C2,C1->C2->C3,C1->C2, C1->C2->C3->C1,C1->C2

若是别的应用程序打开C2,则会新启一个task。
如别的应用Other中有一个activity,taskId为200,从它打开C2,则C2的taskIdI不会为200,例如C2的taskId为201,那么再从C2打开C1、C3,则C2、C3的taskId仍为201。
注意:如果此时你点击home,然后再打开Other,发现这时显示的肯定会是Other应用中的内容,而不会是我们应用中的C1 C2 C3中的其中一个。

4. singleInstance    只有一个实例,并且这个实例独立运行在一个task中,这个task只有这个实例,不允许有别的Activity存在。    此启动模式和我们使用的浏览器工作原理类似,我们都知道在多个程序中访问浏览器时,如果当前浏览器没有打开,    则打开浏览器,否则会在当前打开的浏览器中访问。    此模式会节省大量的系统资源,因为他能保证要请求的Activity对象在当前的栈中只存在一个。

例如:
程序有三个ActivityD1,D2,D3,三个Activity可互相启动,其中D2为singleInstance模式。那么程序从D1开始运行,假设D1的taskId为200,那么从D1启动D2时,D2会新启动一个task,即D2与D1不在一个task中运行。假设D2的taskId为201,再从D2启动D3时,D3的taskId为200,也就是说它被压到了D1启动的任务栈中。

若是在别的应用程序打开D2,假设Other的taskId为200,打开D2,D2会新建一个task运行,假设它的taskId为201,那么如果这时再从D2启动D1或者D3,则又会再创建一个task,因此,若操作步骤为other->D2->D1,这过程就涉及到了3个task了。

3、总结

onNewIntent()方法的调用和singleTop或者singleTask有关。

singleInstance:
第一次进入:onCreate onStart
在栈顶再次进入: onNewIntent
不在栈顶再次进入:onNewIntent onRestart onStart

standard:
第一次进入:onCreate onStart
在栈顶再次进入: onCreate onStart
不在栈顶再次进入:onCreate onStart

singleTop:
第一次进入:onCreate onStart
在栈顶再次进入:onNewIntent
不在栈顶再次进入:onCreate onStart

singleTask:
第一次进入:onCreate onStart
在栈顶再次进入:onNewIntent
不在栈顶再次进入:onNewIntent onRestart onStart

当启动模式为singleTop的时候,Android系统会先检查栈顶的实例是不是该Activity的实例,如果不是的话,它会创建一个该Activity的实例,并启动onCreate函数。如果栈顶已经存在该实例,则不会再创建该Activity的实例,而且不会执行onCreate函数,而是执行onNewIntent函数来重新启动已经存在的实例。

同理,当启动模式为singleTask的时候,若栈顶不是该Activity的实例的时候,系统会在栈中寻找是否存在这个实例,如存在的话就会把这个实例放在栈顶,并把它之前的实例清除掉。但如果栈顶已经是这个实例的话,就会执行onNewIntent函数。道理和singleTop一样。

当调用到onNewIntent(intent)的时候,需要在onNewIntent() 中使用setIntent(intent)赋值给Activity的Intent.否则,后续的getIntent()都是得到老的Intent。