1.Android 主要包含4种启动模式,下面分别介绍四种启动方式的特点:
1)tandard 默认的启动模式,标准模式
每开启一个Activity,就会在栈顶添加一个Activity实例。多次间隔或者直接启动一个甲Activity会添加多个甲的示例,可重复添加。(间隔 ABA, 直接 ACC或者AAA)
这里我们需要明白一个事情,Service和ApplicationContext是没办法直接开启一个新的Activity,因为只有Activity类型的Context的Activity才能开启,但还是有解决办法的,那就是让我们要开的那个新的Activity设置为FLAG_ACTIVITY_NEW_TASK标识。
2)singletop 单一顶部模式 (顶部不会重复)
如果开启的Activity已经存在一个实例在任务栈的顶部(仅限于顶部),再去开启这个Activity,任务栈不会创建新的Activity的实例了,而是复用已经存在的这个Activity,onNewIntent方法被调用;之前打开过,但不是位于栈顶,那么还是会产生新的实例入栈,不会回调onNewIntent方法。
singleTask 单一任务 (整个任务栈只有一个对应自身的实例)
如果开启的甲Activity已经存在一个实例在任务栈S1,再去开启这个Activity,位于栈顶则直接复用,回调onNewIntent方法;位于里面,也是复用,回调onNewIntent方法,复用的同时的是直接把自己上方的全部Activity都干掉。singleInstance 单一实例(单例),任务栈里面自已自己一个人
当启动一个启动模式为singleInstance的Activity时(之前没启动过),这时系统将开辟出另外一个任务栈,用于存放这个Activity,而且这个新的任务栈只能存放自身这唯一一个Activity。singleInstance页面作为前台任务打开自己打开自己,则复用,任务栈顺序无变化;singleInstance页面作为后台任务栈,则切换成为前台任务栈,无新实例产生,复用。
-
Activity任务栈
任务栈中包含了activity组件的对象,且任务栈中可以包含有某一个activity组件类型的多个实例对象。在任务栈中的activity组件不能被重排序,只能被压栈和弹栈。
任务栈不是某个类型,也不是某一个元素,它是一组activity组件的组织形式。所以没有办法在不影响任务栈中的activity组件的情况下,单独设置任务栈的参数。根activity的参数既是整个任务栈的参数,它会影响任务栈中的所有activity组件。
当某个应用程序在前后台切换的时候,实际上就是代表这个应用程序的一个任务栈在前后台切换。刚刚描述的行为是activity和任务栈的默认行为,但也有办法在很多方面对它进行修改:
方法1:在发送的请求(即Intent对象)中设置一些标记。
方法2:在manifest文件中,对接收请求(即Intent对象)的activity组件设置一些属性。
在Intent对象中主要的标志有:
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP在<activity>标签中,主要的属性有:
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
Intent与启动模式相关的Flag简介
这里仅仅对几个常用的与启动模式相关的Flag进行介绍。
1)FLAG_ACTIVITY_NEW_TASK
在google的官方文档中介绍,它与launchMode="singleTask"具有相同的行为。实际上,并不是完全相同!很少单独使用FLAG_ACTIVITY_NEW_TASK,通常与FLAG_ACTIVITY_CLEAR_TASK或FLAG_ACTIVITY_CLEAR_TOP联合使用。因为单独使用该属性会导致奇怪的现象,通常达不到我们想要的效果!2)FLAG_ACTIVITY_SINGLE_TOP
在google的官方文档中介绍,它与launchMode="singleTop"具有相同的行为。实际上,的确如此!单独的使用FLAG_ACTIVITY_SINGLE_TOP,就能达到和launchMode="singleTop"一样的效果。3)FLAG_ACTIVITY_CLEAR_TOP
顾名思义,FLAG_ACTIVITY_CLEAR_TOP的作用清除"包含Activity的task"中位于该Activity实例之上的其他Activity实例。FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK两者同时使用,就能达到 launchMode="singleTask"一样的效果!4)FLAG_ACTIVITY_CLEAR_TASK
FLAG_ACTIVITY_CLEAR_TASK的作用包含Activity的task。使用FLAG_ACTIVITY_CLEAR_TASK时,通常会包含FLAG_ACTIVITY_NEW_TASK。这样做的目的是启动Activity时,清除之前已经存在的Activity实例所在的task;这自然也就清除了之前存在的Activity实例!
注意:当同时使用launchMode和上面的FLAG_ACTIVITY_NEW_TASK等标签时,以FLAG_ACTIVITY_NEW_TASK为标准。也就是说,代码的优先级比manifest中配置文件的优先级更高!android 中activity的任务栈中有几个非常重要的概念:
- taskAffinity
taskAffinity属性用于给Activity单独指定任务栈名称。这个名称不能和包名相同,否则就没有意义。注意taskAffinity属性值为String,而且中间必须包含有分隔符 . (英文状态下的点),比如com.baidu.test.
另外,如果想要指定一个非包名的任务栈,该Activity一定要把启动模式设置为singleTask模式,否则不会生效。如果taskAffinity指定的名称是其他程序的包名,那么可以不结合singleTask。注意:任务栈分为前台任务栈和后台任务栈,后台任务栈里面的Activity全部处于onStop状态。
在minifest里面,application可以设定taskAffinity,activity也可以设定taskAffinity。
taskAffinity设定的任务栈我们也称其为一个宿主任务栈。
(1)application设定
applicatipn如果不设定,那么就系统默认设定为包名。如果设定了,activity跟着application走,application指定的是什么activity的任务栈的名称就是什么。(application自带的不设定,一般我们也不手动设定,要设定也是单独在activity里面设定)
(2)activity设定
设定taskAffinity之后,当启动这个Activity之后,如果之前没有任务栈的存在,那么就启动系统会开辟出来一个新的任务栈(或者叫宿主任务栈),用于存放这个activity,如果已经存在了这个任务栈,那么这个activity就对应进入已经的宿主任务栈。(设定taskAffinity,不管之前存不存在,反正就不跟默认的混了,自己只认指定的任务栈,当然,如果你非要把taskAffinity指定自己的包名那也没办法,只是那没撒意思嘛)。
2)allowTaskReparenting
在说这个属性之前,要先说一下activity的亲属关系,默认情况下,一个应用程序中的activity组件彼此之间是亲属关系――也就是说它们属于同一个任务栈。但是我们可以通过设置某个<activity>标签的taskAffinity属性来为这个activity组件设置亲属关系。在不同的应用程序中定义的activity组件可以共用同一个亲属关系,或者在同一个的应用程序中定义的activity组件可以使用不同的亲属关系。
若一个activity组件的allowTaskReparenting被置为“true”,则当与这个activity有相同的亲属关系的任务栈被切换到前台的时候,这个activity会从当前存在的任务栈中移动到与其有相同的亲属关系的任务栈中。
3)alwaysRetainTaskState属性
如果将根activity的alwaysRetainTaskState属性设置为“true”,则即便一个任务栈在很长的一段时间都被用户保持在后台的,系统也不会对这个任务栈进行清理。
4)clearTaskOnLaunch属性
如果将根activity的clearTaskOnLaunch属性设置为“true”,那么只有这个任务栈切换到了后台,那么系统就会将这个任务栈中除了根activity以外的其它所有activity全部清除掉。即和alwaysRetainTaskState的行为完全相反。
- finishOnTaskLaunch属性
这个属性的行为类似于clearTaskOnLaunch,但是此属性作用于单个的activity对象,而不是整个任务栈。当这个任务栈切换到了后台,这个属性可以使任务栈清理包括根activity在内的任何activity对象。