在熟悉Activity的四种启动模式之前,先明确task的概念:
1. 什么是Task
Task是一个逻辑的概念,用来组织完成同一个功能的Activity,即使这些Activity来自不同的Application。对于用户来说, Android 通过将多个 Activity 保存在同一个 Task 里来体现这一用户体验。简单来说,一个 Task 就是用户体验上的一个“应用”。它将相关的 Activity 组合在一起,以 stack 的方式管理。也就是说stack和task是一一对应的关系,而不是stack和application是一一对应的关系。
2.Activity加载模式的两种设置方法
默认情况下,新启动的Activity都和启动它的人处于同一个task中,但是Android也提供了两种方法来设置Activity加载模式,从而改变默认行为,控制task:
在Android中,每一个Activity的Task模式,都是可以由Activity提供方(通过配置文件...)和Activity使用方(通过Intent中的flag信息...)进行配置和选择。当然,使用方对Activity的控制力,是限定在提供方允许的范畴内进行,提供方明令禁止的模式,使用方是不能够越界使用的。
1> 设置manifest文件中<activity>元素的属性,这些属性包括:
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
2> 设置start Activity()中Intent参数的FLAG,这些FLAG包括:
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_SINGLE_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_REORDER_TO_FRONT
两种方式的差别在于,前者在于描述自己,声明自己如何被加载;而后者则是动态的,指出我要求你如何被加载。
注意:intent中FLAG的优先级比manifest中的属性值要高。
3. manifest中<activity>的launchMode属性
manifest文件中<activity>元素的属性设置:
<activity android:name=".ActivityA"
android:label="ActivityA"
android:launchMode="">
</activity>
launchMode属性有四个属性值:"standard"、"singleTop"、"singleTask"、"singleInstance"。
1>"standard"(默认值)
每次启动,系统都会在启动它的task中创建一个新的实例。
是默认的也是标准的Task模式,在没有其他因素的影响下,使用此模式的Activity,会构造一个Activity的实例,加入到调用者的Task栈中去。
注意:即使Activity在当前task中被加载,但是如果该Activity属于另一个应用,系统也会创建一个新的进程,新启动的Activity也会运行在另外的进程中。所以task应该只是逻辑上的概念。
2>"singleTop"
基本上于standard一致,仅在请求的Activity正好位于栈顶时,有所区别。此时,配置成singleTop的Activity,不再会构造新的实例加入到Task栈中,而是将新来的Intent发送到栈顶Activity中,栈顶的Activity可以通过重载onNewIntent来处理新的Intent(当然,也可以无视...)。
Startup - launch
ActivityA:====> onCreate()
ActivityA: ====>onStart()
ActivityA:====> onPostCreate()
ActivityA:====> onResume()
ActivityA:====> onPostResume()
Start - singleTop
ActivityA:====> onPause()
ActivityA:====> onNewIntent()
ActivityA:====> onResume()
3> "singleTask"
“singleTask”的Activity只允许存在一个实例。
默认情况下,一个新启动的Activity归属于启动它的task(即使启动者所在task的taskAffinity的和SingleTask的Activity的taskAffinity值不匹配)。
当一个应用程序加载singleTask模式的Activity时,系统首先会检查是否存在与singleTask的taskAffinity相同的Task。
1. 如果task存在,检查是否实例化。
1) 如果没有实例化,实例化singleTask并入栈。
2) 如果已经实例化,销毁在singleTask以上的所有Activity并调用onNewIntent()。
2. 如果task不存在,那么就重新创建Task,并实例化singleTask入栈。
栈空间简易示意:A -- B -- C
最后用startActivity(intent)从C跳到A后,由于栈空间已经存在A的实例,A上面的Activity B和C出栈(即onDestroy销毁),A置于栈顶
如果A中重写了onNewIntent(...)方法,会同时接到C跳A的intent数据
4> "singleInstance"
和"singleTask"一样,“singleInstance”的Activity只允许存在一个实例,但是"singleInstance"是所属task中的唯一activity,所有由singleInstance所启动的activity都会被放置到另外的task中启动。
所以,可以看出,与"singleTask"不同的是,当在自身应用中启动singleInstance时,系统会创建一个新的task。而启动singleTask时,系统不会创建新的task,这是因为singleInstance在task中必须是唯一的。
当应用程序加载一个singleInstance模式的Activity时,如果没有被实例化,那么就重新创建一个Task,并实例化入栈,如果已经被实例化,那么就将singleInstance所在的task带到前台,并调用singleInstance的onNewIntent()。
1,起始Activity非singleInstance (实际跳转顺序:A -- B -- C -- A -- B -- C .....)
A,C位于同一栈中,taskId相同, B在另一个栈中,与他们taskId不同,此栈在B未被销毁前只能有B一个Activity(B在创建之后,onNewIntent(...)也可以接到其他Activity跳转的intent数据),整个过程中,B只创建了一次,A与C每次都创建一个实例
2,起始Activity为singleInstance(实际跳转顺序:A -- B -- C -- A -- C -- A -- C .....)
代码中第一种情况相同,但实际跳转顺序却不同,
第一次A -- B -- C 实际跳转完成之后,当从C回到A(A在创建之后,onNewIntent(...)也可以接到其他Activity跳转的intent数据)后,再从A跳B时,却跳到了C页面,依次循环,整个过程中,B只是在一开始创建时出现了一次,之后从A都是直接跳C,A当然是单实例的,但是C也只创建了一次,相当于是单实例
多次跳转按物理返回键时:
如果当前页面是A,则A销毁,出现C,接着C销毁,出现B,B销毁,应用程序结束
如果当前页面是C,则C销毁,出现B,接着B销毁,出现A,A销毁,应用程序结束
返回键的实际跳转情况属于正常,因为A的taskId, 与B,C不同,不在同一栈中.