Activity是Android的四大组件之一,他的重要性毋庸置疑,对于这么重要的一个组件,我们首先要知道这些都是由系统进行管理和回调的,要理解Activity的启动模式,我们首先来了解一下Android中的任务栈。
任务栈Task,是一种用来放置Activity实例的容器,他是以栈的形式进行盛放,也就是所谓的先进后出,2个基本操作:压栈和弹出,所以在其中只能根据压栈和弹出操作更改Activity的顺序。我们启动一个Application的时候,系统会为它默认创建一个对于的Task,用来盛放根Activity,默认启动Activity会放在同一个Task中,新启动的Activity会被压入启动它的那个Activity的栈中,并且显示他,当用户按下回退键时,这个Activity就会被弹出栈,按下Home键回到桌面,再启动另一个应用,这时候之前那个Task就被移到后台,成为后台任务栈,而刚启动的那个Task就被调到前台,成为前台任务栈,Android系统显示的就是前台任务栈中的Top实例Activity,当然,同一个应用可以有多个任务栈,但是肯定只存在一个任务栈在前台。对于任务栈的调配应该大概了解了,下面提一下他的一个重要的属性taskaffinity,也就是所谓的亲和力。这个属性不光Task有,Activity也有(affinity),他们就是通过这个属性值来进行关联的,不然你想想,一个应用有这么多Activity,并且可以有多个task,那么让activity实例随便入哪个栈都行,那岂不是乱成一团了。
affinity系统默认会给他一个值,那就是应用的包名。并且如果自己重新给他值的话就在xml文件中定义,但是他的定义必须包含".",也就是像包名一样中间要有点号。
以上简单的介绍了任务栈,下面我们正式讲下我们的Activity的启动模式和标志位,首先分为四种启动模式,分别为:标准模式,栈顶复用模式,栈内复用模式,单例模式。
1.standard即标准模式,他是系统默认的启动方式,这个任务栈中可以有多个相同的Activity实例,多个相同Activity实例也可以分布在不同的任务栈中,这时候是谁启动他,他就和谁在一个任务栈中,这时候我们要联系到我们遇到过的一个异常:android.util.AndroidRuntimeException:....,具体内容大家试试这样启动一个Activity就会出来,使用ApplicationContext启动一个standard模式的Activity。我们分析下,其实这个错误的出现就是因为默认模式下,被谁启动,activity就翻到那个任务栈中去,而全局的上下文对象是没有任务栈存在的,所以就会报错了,解决这个问题可以更改启动的上下文为某个activity对象,当然我们如果将被启动的activity设置他的标志位为FLAG_ACTIVITY_NEW_TASK 也同样可以,这时候就相当于把Activity改为了singleTask模式启动了。
2.singleTop即栈顶唯一模式,这种模式下,如果Activity位于任务栈的栈顶,那么此Activity不会被重新创建,也就是说不会调用生命周期中的onCreate和onStart方法,但是会回调另一个方法onNewIntent,这时候我们可以在这个回调方法里根据参数Intent intent进行自己的相关处理。如果新启动的Activity实例不存在,或者存在但是不是位于栈顶,那么和正常一样的创建它。
3.singleTask即栈内唯一,这个其实是一种单例模式,只要这个任务栈中存在这个Activity的实例,那么就不再创建它,而是直接复用其实例,这时候也会回调onNewIntent,这时候有个问题,这个实例如果不是在栈顶,那么它要到栈顶来,唯一途径就是把它之前的实例全部弹出,实际上就是说singleTask具有clearTop的效果。当然这是简单的说明,下面几个例子让你更能理解:
例1.目前有S1任务栈中有ABC,这个时候要启动Activity D并且D是singleTask模式,其所需的任务栈为S2(之所以不是S1因为为他指定了affinity属性),这时候由于S2和D都不存在,所以会先创建任务栈S2,然后在创建实例D压入栈底。
例2.情况和1相同,只是D所需任务栈同样是S1,这时候就只要创建D的实例并将其压入到栈S1中即可。
例3.如果D所需的任务栈为S1,并且当前S1中的情况为ADBC,这时候D的实例存在了,那么会将BC出栈,剩下AD,这就是singleTask默认具有clearTop的效果
4.singleInstance 单例模式,这是一种加强型的singleTask,他具有singleTask的所有特性,并且拥有一个独特的地方就是,他会单独占用一个任务栈,比如Activity A是singleInstance模式,那么启动他的时候,系统会为他单独创建一个任务栈将其压入,如果再次启动他,他已经存在了,那么就直接复用该任务栈。
以上就是关于启动模式的说明,注意一点就是TaskAffinity这个属性主要是与singleTask或者allowTaskReparenting属性配对使用,在其他情况下是没有意义的。
下面讲下关于标志位,Activity的标志位Flags有很多种,其效果也有很多,比如可以用来设定启动模式,可以用来影响运行状态,下面介绍几个常用的标志位:
FLAG_ACTIVITY_NEW_TASK
该标志位作用于指定Activity的singleTask启动模式一样。
FLAGE_ACTIVITY_SINGLE_TOP
该标志位的作用和指定Activity的singleTop效果一致。
FLAGE_ACTIVITY_CLEAR_TOP
此标记位的效果就有意思了,拥有它的Activity会将与他在同一个任务栈中之前Activity都出栈,这个标志通常和singleTask配合使用时,如果实例存在,就调用他的onNewIntent,并将他之上的其他实例都清除,但是如果拥有该标志位的Activity是默认启动模式standard,那么他会连同自己一起清除,然后再重新创建实例,这点要注意好,所以之前我们说了singleTask默认具有此标志的效果
以上就是简单的说了一下启动模式和标志位。为Activity设置启动模式我们有2中方式:
1.在XML文件中定义 android:launchMode="singleTask"
2.在启动意图的时候设置:intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
这俩种方式存在一些区别:
优先级第二种大于第一种,当俩种方式同时存在的时候以第二种方式为准,第一种方式为辅。俩种方式也存在适用范围的区别,第一种方式无法直接为Activity设定FLAG_ACTIVITY_CLEAR_TOP标志的效果,而第二种方式无法直接设置出singleInstance模式的效果。
希望看完能让你在开发中对启动模式和flags标志位进行灵活使用~~~