前言
在Andoid
中,Activity
的启动模式可以避免重复创建它,以及在任务栈
中存在多个实例的问题,所以Activity
提供了启动模式(LaunchMode
)来修改系统默认行为,这样可以复用任务栈中的Activity
实例。目前有四种启动模式:standard
、singleTop
、singleTask
和singleInstance
。
LaunchMode
- 1.)standard
标准模式
:系统的默认启动模式,每次启动一个Activity
都会重新创建一个新的实例并放入任务栈,不管这个实例是否已经存在。被创建的实例的生命周期符合典型条件下的生命周期,它的onCreate
、onStart
、onResume
都会被调用。这就是一个多实例的实现,一个任务栈中可以有多个实例,每一个实例都可以在不同的任务栈。在这种模式下,谁启动了这个Activity
,就在谁的任务栈。比如Activity A启动了Activity B
(B是标准模式),那么B就会进入到A的任务栈中。
场景:该种模式大多用于
页面切换的 中间页
,每次都是新页面(适用于大多场景).
- 2.)singleTop
栈顶复用模式
: 这种模式下,如果新的Activity已经位于任务栈的栈顶,那么此Activity
不会重新创建,同时它的onNewIntent
方法会被回调,通过此方法的参数我们取出当前请求的信息。与此同时,这个Activity
的onCreate
,onStart
方法不会被系统调用,因为它并没有发生改变。如果新的Activity的实例已存在但是不位于栈顶,那么新Activity
仍然会重新创建。
场景:singleTop适合接收通知启动的内容显示页面(推送启动的界面)。例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很不友好的,这时候就可以使用此种模式。
- 3.)singleTask
栈内复用模式
:这是一种单实例的模式,只要Activity
在一个栈中存在, 那么多次启动此Activity
都不会重新创建实例,和singleTop
一样,系统也会调用其onNewIntent
。具体来说,当一个具有singleTask
模式的Activity
请求启动后,比如Activity A
,系统会首先去找是否存在A所需要的任务栈,如果不存在,就重新创建一个任务栈,然后创建A的实例。如果存在A所需要的任务栈,这时候要看A在栈中是否有实例存在,如果有实例存在,那么系统就会将A调到栈顶并调用它的onNewIntent方法,同时销毁这个A上所有Activity的实例。如果实例不存在,就创建A的实例并把它压入栈中。
场景:适合作为程序入口点。例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。
- 4.)singleInstance
单实例模式
: 这是一种加强的singleTask
模式,它除了具有singleTask
模式的所有特性外,还加强了一点,那就是具有此种模式的Activity
只能单独地位于一个任务栈中,换句话说,比如Activity A
是singleInstance
模式,当A启动后,系统会为它创建一个新的任务栈,然后A独立在这个新的任务栈中,由于栈内复用的特性,后续的请求均不会创建新的Activity
,除非这个独特的任务栈被系统销毁了。
场景: 适合需要与程序分离开的页面。例如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B。
Flags
除了在AndroidManifest
中设置启动模式,还可以代码中通过Intent.addFlags
设置,这两种还是有一定的区别的,当两种同时存在的时候,以第二种为准。
Activity的Flags有很多,这里主要分析一些比较常见的标记位。
FLAG_ACTIVITY_NEW_TASK
: 这个标记为的效果是为Activity
指定“singleTask”启动模式,和在XML中指定的作用一样
FLAG_ACTIVITY_SINGLE_TOP
:这个标记位的作用是位Activity
指定“singleTop”启动模式,其效果和在XML中指定该启动模式一样
FLAG_ACTIVITY_CLEAR_TOP
:如果设置,并且这个Activity已经在当前的Task中运行,因此,不再是重新启动一个这个Activity的实例,而是在这个Activity上方的所有Activity都将关闭,然后这个Intent
会作为一个新的Intent
投递到老的Activity
(现在位于顶端)中。例如,假设一个Task中包含这些Activity
:A,B,C,D。如果D调用了startActivity()
,并且包含一个指向Activity B
的Intent
,那么,C和D都将结束,然后B接收到这个Intent
,因此,目前stack的状况是:A,B。上例中正在运行的Activity B
既可以在onNewIntent()
中接收到这个新的Intent
,也可以把自己关闭然后重新启动来接收这个Intent。如果它的启动模式声明为默认值,并且你没有在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP
标志,那么它将关闭然后重新创建;对于其它的启动模式,或者在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP
标志,都将把这个Intent
投递到当前这个实例的onNewIntent()
中。这个启动模式还可以与FLAG_ACTIVITY_NEW_TASK
结合起来使用:用于启动一个Task中的根Activity,它会把那个Task中任何运行的实例带入前台,然后清除它直到根Activity。这非常有用,例如,当从Notification Manager
处启动一个Activity
。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
: 具有这个标记的Activity
不会出现在历史Activity
的列表中,当某些情况下我们不希望用户通过历史列表回到我们的Activity
的时候这个标记比较有用,它等同于在XML中指定Activity的属性android:excludeFromRecents="true"
TaskAffinity
(此处借用刘皇叔的文章)
我们可以在AndroidManifest.xml设置android:taskAffinity,用来指定Activity希望归属的栈, 默认情况下,同一个应用程序的所有的Activity都有着相同的taskAffinity,在下面两种情况时会产生效果。
1 .
taskAffinity
与FLAG_ACTIVITY_NEW_TASK
或者singleTask
配合。如果新启动Activity的taskAffinity和栈的taskAffinity相同(栈的taskAffinity
取决于根Activity
的taskAffinity
)则加入到该栈中。如果不同,就会创建新栈。
2 .
taskAffinity
与allowTaskReparenting
配合。如果allowTaskReparenting
为true
,说明Activity
具有转移的能力。当一个应用A启动了一个应用B的某个Activity
后,如果这个Activity
的allowTaskReparenting
属性为true
的话,那么当应用B被启动之后,此Activity
会直接从应用A的任务栈转移到应用B的任务栈。再比如,现在有两个应用A和B,A启动了B的一个Activity C
,然后按Home键回到桌面,然后单击B的桌面图标,这个时候并不是启动了B的主Activity
,而是重新显示了已经被应用A启动的Activity C
,或者说,C从A的任务栈转移到了B的任务栈。可以这么理解,由于A启动了C,这个时候C只能运行在A的任务栈中,但是C属于B,正常情况下,它的TaskAffinity
值不可能和A的任务栈相同。所以当B被启动之后,B会创建自己的任务栈,这个时候系统发现C原本想要用的任务栈已经被创建,所以就把C从A的任务栈中转移过来了,这时候就是显示C的Activity
。
AMS栈管理相关类
关于Activity
的栈对应着Android
系统中的TaskRecord
,而多个TaskRecord
对应着ActivityRecord
,它用来管理所有Activity
的各种状态,其内部维护了TaskRecord
的列表,ActivityRecord
由ActivityStackSupervisor
来管理,而ActivityStackSupervisor
在AMS的构造方法中被创建
public ActivityManagerService(Context systemContext) {
mStackSupervisor = createStackSupervisor();
}
protected ActivityStackSupervisor createStackSupervisor() {
return new ActivityStackSupervisor(this, mHandler.getLooper());
}
结构如下
参考
1.Android开发艺术探索
2.android launchMode理解以及应用场景
3.android launchmode 使用场景
4.Android解析ActivityManagerService(二)ActivityTask和Activity栈管理