Activity的四种启动模式

来源:互联网 发布:java ssh 编辑:程序博客网 时间:2024/06/02 03:03

四种启动模式

  1. standard模式
  2. singleTop模式
  3. singleTask模式
  4. singleInstance模式

1、standard模式

标准模式,这也是系统的默认启动模式。在standard模式下,无论启动的Activity是否已经存在,系统都会在当前启动这个Activity所在的任务栈中,新建一个有完整生命周期的Activity。
举个例子:
有两个Activity A和Activity B,在任务栈1中,有A,此时A去启动B,那么任务栈1中就是AB,A在栈底,B在栈顶;此时B再去启动B自身,那么任务栈1中就是ABB,A是栈底,新启动的B在栈顶;由此可见,无论被启动Activity是否存在,都会被重新创建在启动它的任务栈中。

2、singleTop模式

栈顶复用模式。在singleTop模式下,如果要被启动的Activity已经位于任务栈的栈顶的话,那么这个Activity就不会被重新创建,与此同时,还会回调其onNewIntent方法,这个方法的参数带有当前请求的信息。如果该任务栈没有这个Activity或者不在栈顶的话,就会在栈顶新建这个Activity。
仔细想想,上面的话就会觉得有问题,”被启动的Activity已经位于任务栈的栈顶“,这个任务栈到底是哪个任务栈,所以这里就会出现两种情况,下面举列说明。
假设我们当前我们有四个Activity A, B , C, D
情况一:前台栈中是ABC,A是栈底,C是栈顶,后台栈内是D,那么此时在前台栈中启动D,D是singleTop模式,前台栈的情况是ABCD,后台栈是D,这种情况下D被新建了。
情况二:前台栈中是ABCD,A是栈底,D是栈顶,后台栈内是D,那么此时在前台栈中启动D,D是singleTop模式,前台栈的情况是ABCD,后台栈是D,这种情况下D被复用了。

3、singleTask模式

栈内复用模式。singleTask模式其实是一种单实例模式,只要某个Activity在一个栈中被创建了,那么多次启动这个Activity也都不会再重新创建了,与此同时,系统也会回调onNewIntent。
具有singleTask模式的Activity的执行逻辑如下,当这个Activity被请求启动之后,系统首先会查找是否存在A需要的任务栈(主要就是去匹配taskAffinity属性),如果不存在就创建一个任务栈,然后再创建Activity并压入此任务栈中;如果存在A需要的任务栈,就会查找是否这个任务栈中已经有该Activity了,如果没有,就创建一个压入栈顶,如果有,要是在栈顶就直接回调,要是不在栈顶就把它上面的Activity都弹出栈,让它回到栈顶。
举个例子:
假设我们有两个任务栈S1和S2,Activity A, B, C, D;
情况一:任务栈S1是ABC,A是栈底,C是栈顶;D是singleTask模式,而且需要的任务栈是S2,那么此时启动D的话,系统就会先创建任务栈S2,然后创建D并压入S2;
情况二:在情况一的基础上,D需要的不再是S2了,是S1了,此时系统就会直接创建一个D并压入S1;
情况三:任务栈S1是ABDC,A是栈底,C是栈顶;D是singleTask模式,而且需要的任务栈是S1,那么此时启动D的话,系统就会将C弹出栈,S1变为ABD

4、singleInstance模式

单实例模式。singleInstance可以理解为强化版singleTask模式,它具有singleTask模式的所有特点外,还需要保证具有singleInstance模式的Activity之呢个单独的位于一个任务栈中(这个任务栈就是它的taskAffinity属性)。
执行逻辑:一个Activity具有singleInstance模式,当它被启动的时候,系统首先就会去找这个Activity所需要的栈,如果不存在的话,就先创建这个Activity所需要的任务栈,然后再创建这个Activity并压入栈,以后就再也不会创建这个Activity了;如果存在的话,就把带有这个Activity的栈,置为前台栈,然后再执行singleTask模式的逻辑。

介绍几个Activity相关的属性参数

首先,当我们定义了一个Activity,无论时候调用了,都要在AndroidManifest.xml文件中去声明这个Activity。而对应Activity都存在于任务栈中,任务栈又分为前台栈和后台栈,只能有一个前台栈,但是可以有多个后台栈,后台栈中的Activity都是pause状态。

Activity生命格式如下:

< activity android:allowTaskReparenting=["true" | "false"]    android:alwaysRetainTaskState=["true" | "false"]    android:clearTaskOnLaunch=["true" | "false"]    android:configChanges=["mcc", "mnc", "locale",        "touchscreen", "keyboard", "keyboardHidden",        "navigation", "screenLayout", "fontScale", "uiMode",        "orientation", "screenSize", "smallestScreenSize"]    android:enabled=["true" | "false"]    android:excludeFromRecents=["true" | "false"]    android:exported=["true" | "false"]    android:finishOnTaskLaunch=["true" | "false"]    android:hardwareAccelerated=["true" | "false"]    android:icon="drawable resource"    android:label="string resource"    android:launchMode=["multiple" | "singleTop" |        "singleTask" | "singleInstance"]    android:multiprocess=["true" | "false"]    android:name="string"    android:noHistory=["true" | "false"]     android:parentActivityName="string"     android:permission="string"    android:process="string"    android:screenOrientation=["unspecified" | "behind" |        "landscape" | "portrait" |        "reverseLandscape" | "reversePortrait" |        "sensorLandscape" | "sensorPortrait" |        "userLandscape" | "userPortrait" |        "sensor" | "fullSensor" | "nosensor" |        "user" | "fullUser" | "locked"]    android:stateNotNeeded=["true" | "false"]    android:taskAffinity="string"    android:theme="resource or theme"    android:uiOptions=["none" | "splitActionBarWhenNarrow"]    android:windowSoftInputMode=["stateUnspecified",        "stateUnchanged", "stateHidden",        "stateAlwaysHidden", "stateVisible",        "stateAlwaysVisible", "adjustUnspecified",        "adjustResize", "adjustPan"] >     . . .< /activity >

有以下几个比较常见属性(个人看法):

taskAffinity:任务相关性或者任务亲和性(这是目前见的最多的翻法),它的功能就是指定或者标识一个Activity所需要的任务栈的名字,默认情况下都是包名+当前Activity的类名;这个属性一般都是和singleTask模式或者allowTaskReparating属性配对使用,其他情况下也没什么意义。

launchMode:可选项只有standard,singleTop,singleTask,singleInstance这四种模式,上文已经介绍过了。

allowTaskReparenting:当某个拥有相同 taskAffinity 的任务即将返回前台时,Activity 是否能从启动时的任务栈转移至此任务栈中去 —“true”表示可以移动,“false”表示它必须留在启动时的任务中。默认值是“false”。
通常在启动时,Activity 与启动时的任务相关联,并在整个生命周期都位于此任务栈中。 利用本属性可以强行让 Activity 在当前任务栈不再显示时归属于另一个与其 taskAffinity 相同的任务栈。 典型应用是让一个应用程序的 Activity 转移到另一个应用程序关联的主任务栈中去。
举个例子:假设存在两个应用程序 A,B,B中有一个Activity X,allowTaskReparenting属性为true,
A启动了B的X,然后返回了主界面,又去启动了B,此时不会跳转到B的主Activity,而是把在A的任务栈中的X转移到了B的任务栈,去显示X。道理嘛,大概是这样的,正常情况下,A中的Activity的taskAffinity是不可能和B相同(包名限制),然后呢,B启动了,它发现X需要的任务栈已经被创建了,就直接把X从A的任务栈中转移过来了。

当用户长时间把某个应用程序后台,系统会回收这个应用程序的任务栈,只保留栈底的Activity,再次打开的时候就是栈底的Activity,而通过修改clearTaskOnLaunch,alwaysRetainTaskState,finishOnTaskLaunch属性可以改变这种现象。

clearTaskOnLaunch:默认为false,置为true时,则每当用户再次启动任务时都会进入栈底 Activity, 无论之前在此任务中做过什么操作,还是短暂的将应用后台,也无论上次是用 Back 还是 Home 键离开任务的。

alwaysRetainTaskState:系统是否一直维持 Activity 所属任务的状态,一旦本属性设为“true”,则不论用户位于何处,将总是返回任务的最后状态。 与clearTaskOnLaunch相反

finishOnTaskLaunch: 与clearTaskOnLaunch相似,但它只对单独的activity操 作,而不是整个Task。它可以结束任何Activity,包括栈底的Activity。 当它设置为true时,当前的Activity只在当前会话期间作为Task的一部分存在, 当用户退出Activity再返回时,它将不存在。

可以看更多的属性意义(自行戳下面的链接):

http://blog.sina.com.cn/s/blog_48d491300100zmg0.html

四个用于Intent的标志位

FLAG_ACTIVITY_NEW_TASK:
在google的官方文档中介绍,它与launchMode=”singleTask”具有相同的行为。实际上,并不是完全相同!很少单独使用FLAG_ACTIVITY_NEW_TASK,通常与FLAG_ACTIVITY_CLEAR_TASK或FLAG_ACTIVITY_CLEAR_TOP联合使用。

FLAG_ACTIVITY_CLEAR_TOP:顾名思义,FLAG_ACTIVITY_CLEAR_TOP的作用清除”包含Activity的task”中位于该Activity实例之上的其他Activity实例。FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK两者同时使用,就能达到和launchMode=”singleTask”一样的效果!

FLAG_ACTIVITY_SINGLE_TOP:
在google的官方文档中介绍,它与launchMode=”singleTop”具有相同的行为。实际上,的确如此!

FLAG_ACTIVITY_CLEAR_TASK:
FLAG_ACTIVITY_CLEAR_TASK的作用包含Activity的task。使用FLAG_ACTIVITY_CLEAR_TASK时,通常会包含FLAG_ACTIVITY_NEW_TASK。这样做的目的是启动Activity时,清除之前已经存在的Activity实例所在的task;这自然也就清除了之前存在的Activity实例!

具体此时,开门左转:

[http://wangkuiwu.github.io/2014/06/26/IntentFlag/]

叨叨一下Activity的两种启动方式

1、在AndroidMenifest中指定
这里写图片描述
2、通过Intent指定标志位
这里写图片描述

比较:两种方式都可以指定Activity的启动模式,后者的优先级要高于前者,同时存在的情况下,以后者为准;另外第一种方式没有办法指定FLAG_ACTIVITY_CLEAR_TOP标识,第二种办法没法指定Activity的singleInstance模式。

最后

给自己留个坑,有时间把测试代码补上!!

参考资料
https://inthecheesefactory.com/blog/understand-android-activity-launchmode/en

0 0