Activity的启动模式以及栈管理

前言


Andoid中,Activity的启动模式可以避免重复创建它,以及在任务栈中存在多个实例的问题,所以Activity 提供了启动模式(LaunchMode)来修改系统默认行为,这样可以复用任务栈中的Activity实例。目前有四种启动模式:standardsingleTopsingleTasksingleInstance

LaunchMode


  • 1.)standard

标准模式:系统的默认启动模式,每次启动一个Activity都会重新创建一个新的实例并放入任务栈,不管这个实例是否已经存在。被创建的实例的生命周期符合典型条件下的生命周期,它的onCreateonStartonResume都会被调用。这就是一个多实例的实现,一个任务栈中可以有多个实例,每一个实例都可以在不同的任务栈。在这种模式下,谁启动了这个Activity,就在谁的任务栈。比如Activity A启动了Activity B(B是标准模式),那么B就会进入到A的任务栈中。

这里写图片描述

场景:该种模式大多用于 页面切换的 中间页,每次都是新页面(适用于大多场景).

  • 2.)singleTop

栈顶复用模式: 这种模式下,如果新的Activity已经位于任务栈的栈顶,那么此Activity不会重新创建,同时它的onNewIntent 方法会被回调,通过此方法的参数我们取出当前请求的信息。与此同时,这个ActivityonCreateonStart 方法不会被系统调用,因为它并没有发生改变。如果新的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 AsingleInstance模式,当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 BIntent,那么,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 . taskAffinityFLAG_ACTIVITY_NEW_TASK或者singleTask配合。如果新启动Activity的taskAffinity和栈的taskAffinity相同(栈的taskAffinity取决于根ActivitytaskAffinity)则加入到该栈中。如果不同,就会创建新栈。


2 . taskAffinityallowTaskReparenting配合。如果allowTaskReparentingtrue,说明Activity具有转移的能力。当一个应用A启动了一个应用B的某个Activity后,如果这个ActivityallowTaskReparenting属性为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 的列表,ActivityRecordActivityStackSupervisor 来管理,而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栈管理

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值