在多Activity开发中,有可能是自己应用之间的Activity跳转,或者夹带其他应用的可复用Activity。可能会希望跳转到原来某个Activity实例,而不是产生大量重复的Activity。这需要为Activity配置特定的加载模式,而不是使用默认的加载模式。
Activity有四种加载模式,在AndroidManifest.xml文件中activity元素的android:launchMode属性进行配置:
standard singleTop singleTask singleInstance
这四种模式又分为两类,standard和singleTop属于一类,singleTask和singleInstance 属于一类,他们主要有以下不同
1、如何决定所属Task
Standard 和 singleTop 的activity的目标task和收到的Intent的发送者在同一个Task内。除非intent包括参数FLAG_ACTIVITY_NEW_TASK。而且如果提供了FLAG_ACTIVITY_NEW_TASK参数,会启动到别的Task里。
singleTask和singleInstance 总是把Activity作为一个task的根元素,他们不会被启动到一个其他的task里。
2、是否允许多个实例
Standard 和 singleTop 可以被实例化多次,并且存在于不同的task中,且一个task可以包括一个Activity的多个实例。
singleTask和singleInstace则限制只生成一个实例,并且是task的根元素。
singleTop要求如果创建intent的时候栈顶已经有要创建的Activity的实例,则将Intent发送给该实例,而不发送给新的实例
3、是否允许其它activity存在于本Task内
singleInstance 独占一个task,其它activity不能存在那个task里,如果它启动了一个新的avtivity,不管新的Activity的lanuch mode如何,新的Activity都将会得到别的task里运行(如同加FLAG_ACTIVITY_NEW_TASK参数)
另外三种模式。则可以和其它Activity共存。
4、是否每次都生成新实例
standard对于每一个启动Intent都会生成一个Activity的新实例。
singleTop的avtivity如果在task的栈顶的话,则不生成新的该实例。
singleInstace是其所在栈的唯一Activity,它会每次都被重用。
singleTask如果在栈顶,则接受Intent,否则,该Intent会被丢弃,但是访Task仍会回到前台。
Lanuch Mode | 是否允许多个实例 | 是否每次都生成新实例 | 是否允许其他Activity存在于本Task内 | 如何决定所属Task |
standard | 可以被多次实例化,同一个Activity中的不同实例可以存在于不同的Task中,同一个Task也可以存在多个Activity实例 | 是 | 允许 | 存放于StartActivity()的Task。除非设置FLAG_ACTIVITY_NEW_TASK标识 |
singleTop | 同Standard | 如果寄存Activity的栈顶为该Activity,则直接用该Activity实例;否则创建新实例 | 允许 | 同Standard |
singleInstace | 不能有多个实例,由于该模式下Activity总是存在于栈顶,所以Activity在同一实例里至多只有一个实例 | 只有在第一次才创建新的实例,其他情况复用该Activity | 允许。如果存放singleTask的寄存Task内,相应一个工Intent时,如果singleTask位于栈顶,则处理Intent,否则会丢失Intent,但该Task会处于前台 | 存放新的Task内,并且位于该Task的根,不会存放于其他的Task。 |
singleTask | 同singleTask | 同singleTask | 不允许 | 同singleTask |
standard: 标准模式,一调用startActivity()方法就会产生一个新的实例。
singleTop: 如果已经有一个实例位于Activity栈的顶部时,就不产生新的实例,而只是调用Activity中的newInstance()方法。如果不位于栈顶,会产生一个新的实例。
singleTask: 会在一个新的task中产生这个实例,以后每次调用都会使用这个,不会去产生新的实例了。
singleInstance: 这个跟singleTask基本上是一样,只有一个区别:在这个模式下的Activity实例所处的task中,只能有这个activity实例,不能有其他的实例。
下面是影响加载模式的一些特性
1.核心的Intent Flag有:
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP
如应用中的操作:
FLAG_ACTIVITY_CLEAR_TOP FLAG_ACTIVITY_REORDER_TO_FRONT FLAG_ACTIVITY_SINGLE_TOP
如果已经启动了四个Activity:A,B,C和D。在D Activity里,我们要跳到B Activity,同时希望C finish掉,可以在startActivity(intent)里的intent里添加flags标记,如下所示:
Intent intent = new Intent(this, B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
这样启动B Activity,就会把D,C都finished掉,如果你的B Activity的启动模式是默认的(multiple) ,则B Activity会finished掉,再启动一个新的Activity B。
如果不想重新再创建一个新的B Activity,则在上面的代码里再加上:
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
这样B Activity就会再创建一个新的了,而是会重用之前的B Activity,同时调用B Activity的onNewIntent()方法。
如果已经启动了四个Activity:A,B,C和D,在D Activity里,想再启动一个Actvity B,但不变成A,B,C,D,B,而是希望是A,C,D,B,则可以像下面写代码:
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
Activity的加载模式受启动Activity的Intent对象中设置的Flag和manifest文件中Activity的元素的特性值交互控制。
如果当前活动采用非多重启动模式(如singleTop),或意图有Intent.FLAG_ACTIVITY_SINGLE_TOP标志设置,那么当前活动将继续运行,Activity.onNewIntent()方法调用。
如果新的意图是与前一个相同,而新的意图没有Intent.FLAG_ACTIVITY_CLEAR_TOP设置,那么当前的活动将继续运行原样。否则,目前的活动将结束,一个新的开始
2.核心的特性有:
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
常用:android:allowTaskReparenting
用法<application android:allowTaskReparenting="true/false"></application>
是否允许activity更换从属的任务,比如从短信息任务切换到浏览器任务。用来标记Activity能否从启动的Task移动到有着affinity的Task(当这个Task进入到前台时)—— “true”,表示能移动,“false”,表示它必须呆在启动时呆在的那个Task里。
如果这个特性没有被设定,设定到<application>元素上的allowTaskReparenting特性的值会应用到Activity上。默认值为“false”。
一般来说,当Activity启动后,它就与启动它的Task关联,并且在那里耗尽它的整个生命周期。当当前的Task不再显示时,你可以使用这个特性来强制Activity移动到有着affinity的Task中。典型用法是:把一个应用程序的Activity移到另一个应用程序的主Task中。
例如,如果e-mail中包含一个web页的链接,点击它就会启动一个Activity来显示这个页面。这个Activity是由Browser应用程序 定义的,但是,现在它作为e-mail Task的一部分。如果它重新宿主到Browser Task里,当Browser下一次进入到前台时,它就能被看见,并且,当e-mail Task再次进入前台时,就看不到它了。
Actvity的affinity是由taskAffinity特性定义的。Task的affinity是通过读取根Activity的affinity 决定。因此,根据定义,根Activity总是位于相同affinity的Task里。由于启动模式为“singleTask”和 “singleInstance”的Activity只能位于Task的底部,因此,重新宿主只能限于“standard”和“singleTop”模 式。
android:alwaysRetainTaskState
用法<activity android:alwaysRetainTaskState="true/false"></activity>
用来标记Activity所在的Task的状态是否总是由系统来保持——“true”,表示总是;“false”,表示在某种情形下允许系统恢复Task 到它的初始化状态。默认值是“false”。这个特性只针对Task的根Activity有意义;对其它Activity来说,忽略之。
一般来说,特定的情形如当用户从主画面重新选择这个Task时,系统会对这个Task进行清理(从stack中删除位于根Activity之上的所有Activivity)。典型的情况,当用户有一段时间没有访问这个Task时也会这么做,例如30分钟。
然而,当这个特性设为“true”时,用户总是能回到这个Task的最新状态,无论他们是如何启动的。这非常有用,例如,像Browser应用程序,这里有很多的状态(例如多个打开的Tab),用户不想丢失这些状态。
android:clearTaskOnLanunch
用法<activity android:clearTaskOnLanunch=”true/false”></activity>
用来标记是否从Task中清除所有的Activity,除了根Activity外(每当从主画面重新启动时)——“true”,表示总是清除至它的 根 Activity,“false”表示不。默认值是“false”。这个特性只对启动一个新的Task的Activity(根Activity)有意义;对Task中其它的Activity忽略。
当这个值为“true”,每次用户重新启动这个Task时,都会进入到它的根Activity中,不管这个Task最后在做些什么,也不管用户是使 用 BACK还是HOME离开的。当这个值为“false”时,可能会在一些情形下(参考alwaysRetainTaskState特性)清除Task的 Activity,但不总是。
假设,某人从主画面启动了Activity P,并从那里迁移至Activity Q。接下来用户按下HOME,然后返回Activity P。一般,用户可能见到的是Activity Q,因为它是P的Task中最后工作的内容。然而,如果P设定这个特性为“true”,当用户按下HOME并使这个Task再次进入前台时,其上的所有的 Activity(在这里是Q)都将被清除。因此,当返回到这个Task时,用户只能看到P。
如果这个特性和allowTaskReparenting都设定为“true”,那些能重新宿主的Activity会移动到共享affinity的Task中;剩下的Activity都将被抛弃,如上所述。