引言: Activity为什么需要启动模式?
在默认的情况下我们多次启动一个Activity的时候,Activity会创建相应的实例放入到任务栈中,然后我们按back键返回就会发现要一层一层的返回前面创建的Activity.这里我们就发现了一个问题,在默认的启动模式下,Activity会重复创建很多次.而在实际的应用当中,每一个Activity都是进行不同的事物处理.以邮件客户端为例:InBoxActivity就是为了要展示收件箱的,这个Activity不建议创建多个Activity实例.而EditEmailActivity是用来编辑邮件的,就可以实例化多个Activity对象.可以看得出来,合理的设计Activity是否使用已有的实例,还是多次创建,能够为用户带来良好的交互体验.所以Activity的启动需要启动模式.
首先说下Activity的任务栈
Activity的任务栈,又叫回退栈(BackStack).是一种后进先出的数据结构.当我们在启动一个应用程序的时候,如果这个应用程序之前没有被启动过,那么它会创建一个新的任务栈,而把Activity的入口Activity作为这个任务栈的根activity.一个任务栈就是一个activity的集合.
活动的状态(每个活动在其生命周期内最多出现4种状态):
1.前台状态(获取焦点状态或运动状态)
当一个活动处于返回栈的栈顶的时候,这个活动就是处于运行状态的,也可以说是处于前台状态的.系统最不愿意回收掉的就是这种状态的Activity,因为会造成很差的用户体验.
2.暂停状态
当一个活动不再处于栈顶的位置,但是仍然是部分可见的,这时活动就处于暂停状态.这时活动依然是完全存活的,系统也不愿意回收这类活动.
3.停止状态
当一个活动不再处于栈顶的位置,而且是完全不可见的时候,就进入了停止状态.系统仍然会保存这种活动的状态和成员变量,但是这也不是总是可靠的,因为当系统内存资源不足的时候,这种活动是有可能被系统回收掉的.
4.销毁状态
当一个活动从返回栈中移除以后就变成了销毁状态.系统最倾向于回收掉处于这种状态的活动,从而保证手机的内存充足.
活动的四种启动模式
1.standard(标准模式,默认模式)
所有的活动在默认的情况下使用的就是这种模式,标准模式指的是启动这个Activity的时候,它不会去做任何的检测,总是创建一个新的Activity的实例,并使其压栈处于栈顶位置.
2.singTop(单栈顶模式)
singTop模式下的活动在启动的时候,系统会去查看任务栈的栈顶是否是要启动的活动,如果栈顶已经是当前要启动的活动,则其会直接拿来使用.如果栈顶不是将要启动的活动,它就会创建一个新的活动实例,并让其处于任务栈的栈顶位置.
3.singTask(单任务栈模式)
singTask末实现的活动启动的时候,系统会去活动的任务栈中遍历查询是否存在将要启动的活动的实例,如果存在,则会将处于该活动上面的栈内任务弹出(如果有的话),使其处于栈顶的位置.如果不存在,则会重新创建一个新的活动的实例.
4.singInstance(单实例模式(特殊任务栈模式))
这是一种加强版的singleTask模式,它除了具有singleTask模式的所有的特性之外呢,还有一个特性:具有这种模式的Activity只能单独的处于一个任务栈中.
这样它就可以让多个进程之间共享同一个Activity实例.
如何定义启动模式?
启动模式允许你去定义如何将一个Activity的实例和当前的任务进行关联.
-
有两种方式:
1> 使用AndroidManifest.xml文件
可以设置其launchMode属性,来指定它的启动模式为
standard | singTop | singTask | singleInstance中的一种.
2> 使用Intent flag
当调用startActivity(intent)方法的时候,你可以在intent中加入一个flag,从而指定新启动的activity该如何与当前任务相关联.举个例子,如果Activity E启动了Activity F,这个时候Activity F可以在清单文件中配置启动模式来决定自己如何的启动,也可以通过Activity启动它的时候的intent里指定flag来决定它该如何的启动.并且使用intent添加flag的方法会覆盖掉清单文件中的配置启动模式.
首先介绍下Activity在AndroidMenifest.xml中可以设置的属性:
- taskAffinity
- launchMode
- allowTaskReparenting
- clearTaskOnLaunch
- alwaysRetainTaskState
- finishOnTaskLaunch
1. taskAffinity(亲和性)
task是一个Activity的集合,并且对于属于这个task的Activity它也有标识的方法,就是通过affinity来进行标识的.默认情况下,一个应用内的所有的Activity都具有相同的affinity值,都是从Application(参考Application的taskAffinity属性)继承而来,值为app默认的包名.当然也可以为每个Activity设置不同的taskAffinity值.taskAffinity只有在以下两种情况下才有作用:
1>启动一个Activity的过程中Intent使用了FlAG_ACTIVITY_NEW_TASK标记.
2>当一个Activity的allowTaskReprentind设置为true的时候.亲和性相同的Activity就能从启动时所在的任务移动到另一个出现在前台的任务.
2.android:allowTaskReparenting
这个属性用来标记一个Activity实例在当前应用退居后台之后,是否能够从启动它的那个task移动到共同affinity的task,"true"表示可以移动,默认flase表示必须待在启动它的task当中.
3.android:alwaysRetainTaskState
这个属性用来标记应用的task是否保持原来的状态,"true"表示总是保持,默认值false表示不能够保证.此属性只对task的根Activity起作用,其他的Activity都会被忽略.默认情况下,如果一个Activity在后台待太久例如30分钟,用户再次选择该应用的时候,系统就会对该应用的task进行清理,除了跟Activity外,其他的Activity都会被清除出栈.但是如果指定了这个属性为true的时候,它就能保持原来的状态,而不做清理.例如,浏览器应用,用户打开了很多的标签,又不想丢失这些标签,这个时候这个属性就非常的有用.
4.android:clearTaskOnLaunch
这个属性和alwaysRetainTaskState相反,他是用来标识是否从task清除除了根Activity之外所有的Activity,默认是false不清除.同样这个属性只对根Activity起作用,其他的Activity都会被忽略.如果设置这个属性为true,则每次启动Activity的时候,都只会看到根Activity,task中的其他的Activity都会被清除出栈.
5.android:finishOnTaskLaunch
这个属性和android:clearTaskOnLaunch属性相似,但是它作用于单个的Activity,而不是整个的task.它可以导致任何的Activity离开,包括根Activity.但它设置为True的时候,作为任务一部分的activity只会对当前的会话有效.如果用户离开,然后返回到任务中,这个Activity将不复存在.
下面说下常用的Flag的作用:
- FLAG_ACTIVITY_NEW_TASK
设置这个flag,系统会寻找一个task或创建一个新的task来放置目标Activity.
首先它会依据目标Activity的taskAffinity属性进行匹配,如果找到一个task的taskAffinity与之相同,就将目标Activity压入此task中,如果找不到匹配的task,则会创建一个新的task.所以这个标记并不总是启动一个新的task.
- FLAG_ACTIVITY_SINGLE_TOP
和singTop效果相同.当要启动的Activity已经处于栈顶就不再创建直接使用
- FLAG_ACTIVITY_CLEAR_TOP
如果在栈中发现有这个Activity的实例,则会清空这个Activity之上的其他的Activity,让其处于栈顶位置.简而言之,就是跳转到的Activity若已经在栈中存在,则其所在栈中在它上面的所有的Activity都销毁掉(弹栈).
- FLAG_ACTIVITY_NO_HISTORY:
如果当前栈内情况是A->B->C,现在由C启动D的时候,intent里面加了一个
FLAG_ACTIVITY_NO_HISTORY属性,则这个时候D并不会出现在任务栈中,如果这个时候在D的界面又启动了一个Activity E,则这个时候栈的Activity的情况是A->B->C->E,D根本不会出现在任务栈中,如果在E Activity显示的时候按返回键,则会直接出现C Activity,而不会出现D.