准备知识
为什么需要启动模式
在Android开发中,我们都知道,在默认的情况下,如果我们启动的是同一个Activity的话,系统会创建多个实例并把它们一一放入任务栈中。当我们点击返回(back)键,这些Activity实例又将从任务栈中一一移除,遵循的原则是“后进先出”(先进后出)。
这里我们考虑一个问题,当我们多次启动同一个Activity,系统也会创建多个实例放入任务栈中,这样岂不是很耗费内存资源?为了解决这一问题,Android为Actiivty提供了启动模式。启动模式
Activity的启动模式有四种:standard
、singleTop
、singleTask
和singleInstance
。-
如何使用
<activity android:name=".DemoActivity" <!-- value 可以设为启动模式中任意一种,默认standard --> android:launchMode="singleTop" > </activity>
启动模式的分类
标准模式:standard
- 这种启动模式为标准模式,也是
默认模式
- 每当我们启动一个Activity,系统就会相应的创建一个实例,不管这个实例是否已经存在
- 这种模式,一个栈中可以有多个实例,每个实例也都有自己的任务栈。而且是谁启动了此Activity,那么这个Activity就运行在启动它的Activity所在的栈中。
- 【跨进程】这种方式启动的Activity被跨进程调用
- 系统5.0之前:新启动的Activity实例会放入发送Intent的Task的栈的顶部,尽管它们属于不同的程序,这似乎有点费解看起来也不是那么合理
- 系统5.0之后:上述情景会创建一个新的Task,新启动的Activity就会放入刚创建的Task中,这样就合理的多了
栈顶复用模式:singleTop
- 当前栈中不存在该Activity的实例时:其行为同standard启动模式
- 当前栈中已有该Activity的实例并且该实例位于栈顶时:不会创建实例,而是复用栈顶的实例,并且会将Intent对象传入,回调onNewInten()方法
- 当前栈中已有该Activity的实例但是该实例不在栈顶时:其行为和standard启动模式一样,依然会创建一个新的实例
- 【跨进程】这种方式启动的Activity被跨进程调用表现同standard
栈内复用模式:singleTask
在复用的时候,首先会根据taskAffinity
去找对应的任务栈:
- 如果不存在指定的任务栈,系统会新建对应的任务栈,并新建Activity实例压入栈中
- 如果存在指定的任务栈,则会查找该任务栈中是否存在该Activity实例
a、如果不存在该实例,则会在该任务栈中新建Activity实例
b、如果存在该实例,则会直接引用,并且回调该实例的onNewIntent()方法。并且任务栈中该实例之上的Activity会被全部销毁 - 【跨进程】这种方式启动的Activity被跨进程调用表现同standard
单实例模式:singleInstance
该实例为系统唯一,不同的应用去打开这个activity 共享公用的同一个activity。他会运行在自己单独,独立的任务栈里面,并且任务栈里面只有他一个实例存在。启动该模式Activity的时候,会查找系统中是否存在:
- 不存在,首先会新建一个任务栈,其次创建该Activity实例
- 存在,则会直接引用该实例,并且回调onNewIntent()方法
LaunchMode Flag
Activity 的启动模式除了在 AndroidManifest 文件中设置以外,还可以通过 Intent的 Flag 来设置:
FLAG_ACTIVITY_NEW_TASK
使用一个新的任务栈 Task 来启动一个 Activity,但启动的每个Activity都将在一个新的任务栈 Task 中。该 Flag 通常使用在从Service 中启动 Activity 的场景,由于Service中并不存在Activity 任务栈,所以使用该 Flag 来创建一个新的Activity栈,并创建新的 Activity 实例。FLAG_ACTIVITY_SINGLE_TOP
使用 singletop 模式启动一个Activity, 当这个Activity位于历史stack的顶端运行时,不再创建一个新的Activity实例;
与指定android:launchMode=“singleTop”
效果相同FLAG_ACTIVITY_CLEAR_TOP
销毁目标Activity和它之上的所有Activity,重新创建目标Activity
与指定android:launchMode=“singleTask”
效果相同FLAG_ACTIVITY_NO_HISTORY
一个 Activity 使用这种模式启动后,当该 Activity 启动其他Activity后,该 Activity 自己就消失了,不会保留在Activity栈中。FLAG_ACTIVITY_BROUGHT_TO_FRONT
在launchMode中设置singleTask模式时系统会设定。FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
如果设置,新的Activity不会在最近启动的Activity的列表中保存。FLAG_ACTIVITY_FORWARD_RESULT
如果设置,并且这个Intent用于从一个存在的Activity启动一个新的Activity,那么,这个作为答复目标的Activity将会传到这个新的Activity中。这种方式下,新的Activity可以调用setResult(int),并且这个结果值将发送给那个作为答复目标的 Activity。FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
这个标志一般不由应用程序代码设置,如果这个Activity是从历史记录里启动的(常按HOME键),系统会设定。
任务栈
任务栈Task,是一种用来放置Activity实例的容器,他是以栈的形式进行盛放,也就是所谓的先进后出,主要有2个基本操作:压栈和出栈,其所存放的Activity是不支持重新排序的,只能根据压栈和出栈操作更改Activity的顺序。
启动一个Application的时候,系统会为它默认创建一个对应的Task,用来放置根Activity。默认启动Activity会放在同一个Task中,新启动的Activity会被压入启动它的那个Activity的栈中,并且显示它。当用户按下回退键时,这个Activity就会被弹出栈,按下Home键回到桌面,再启动另一个应用,这时候之前那个Task就被移到后台,成为后台任务栈,而刚启动的那个Task就被调到前台,成为前台任务栈,Android系统显示的就是前台任务栈中的Top实例Activity。