为什么Activity需要启动模式呢?在默认情况下,当我们多次启动一个Activity时,系统会创建多个实例并把它们一一放入任务栈中,当我单机Back键时,这些Activity一一回退。任务栈是一个栈,所以是一种后进先出的数据结构。
知道了任务栈的原理,我们就知道为什么需要启动模式了。不然多次启动一个Activity,就创建多个实例,这不是很傻吗?确实很少,Activtiy设计者不可能没有考虑到这个问题,这就是启动模式的意义。
Activity的启动模式(LaunchMode)
standard(标准模式)
标准模式,也就是系统的默认模式。每次启动一个Activity都会重新创建一个新的实例,不管它是否已经存在。在这种模式下,谁启动了这个Activity,那么这个Activity就运行在启动他的那个Activity所在的任务栈中。
当我们用ApplicationContext去启动一个standard模式的Activity时,就会报错,因为ApplicationContext没有任务栈啊,解决这个问题的办法就是为待启动的Activity指定FLAG_ACTIVITY_NEW_TASK标志位,这样启动的时候就会为它创建一个新的任务栈,这时候启动Activity其实是singleTask。
Intent intent = new Intent(getApplicationContext(),LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
singleTop(栈顶复用模式)
在这种模式下,如果新的Activity已经位于栈顶了,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法的参数我们可以去除当前请求的信息。需要注意的是,这个Activity的onCreate和onStart不会被回调。如果新的Activity已经存在,但是不是位于栈顶,那么还是会重新创建一个实例。
singleTask(站内复用模式)
这是一种单例模式,在这种模式下,只要Activity在这个栈内存在,那么多次启动这个Activity都不会重新创建实例,和singleTop一样,也会回调onNewIntent方法。
但是要记住任务栈是栈结构的。所以要想把栈中的元素切换到栈顶,需要把上面的所有元素全部出栈。也就是在这个Activity之上的Activity都会出栈。
singleInstance(但实例模式)
这是一个加强的singleTask模式,它除了具有singleTask模式的所有特性之外,还加强了一点,那就是具有此模式的Activity只能单独的位于一个任务栈中。
任务栈
需要从一个参数说起TaskAffinity。
<activity
android:taskAffinity="login"
android:name=".activity.LoginActivity"
android:label="@string/title_activity_login" />
这个参数标识了一个Activity所需要的任务栈的名字,默认情况下,所需任务栈的名字和包名一样。当然我们可以指定这个参数,必须不能喝包名一样,不然等于没指定。
TaskAffinity主要和singleTask,allowTaskReparenting属性配对使用。
1,当TaskAffinity和singleTask配对使用时,Activity的任务栈的名字就是TaskAffinity。
2,当TaskAffinity和allowTaskReparenting配对使用时,会产生复杂的效果。当一个应用A启动了应用B的一个Activity后,如果这个Activity的allowTaskReparenting为true,那么当应用B被启动后,这个Activtiy的任务栈被从应用A中转移到应用B。
指定启动模式
一种方法:
<activity
android:launchMode="singleInstance"
android:taskAffinity="login"
android:name=".activity.LoginActivity"
android:label="@string/title_activity_login" />
另一种方法:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
这两种方法都可以指定启动模式,但是还是由区别的。首先,优先级上第二种更高,会覆盖第一种;其次,这两种方法在限定范围上不同,第一种无法直接为Activity设置FLAG_ACTIVITY_CLEAR_TOP标识,而第二种无法设置singleInstance。第二种方法可以更精细的指定,请看下面截图: