Activity任务和返回栈机制(activity之间的启动)

android系统任务管理和返回栈的方式是后进先出的方式,就是把所有的activity放入到一个相同的任务当中,通过一个后进先出的一个任务栈管理,这样的方式在大多数的情况下是没有问题的。开发者也无需关心任务栈中的activity是如何保存在返回栈中的。如果你想打破这种默认的行为,比如启动一个新的activity时,你希望它可以存在一个独立的任务栈中,而不是现有的任务中,或者说,当启动一个activity时,这个activity已经存在与返回栈中,你希望把这个activity直接移动到栈顶,而不是在创建一个activity的实例。再或者,你希望可以将返回栈中的除了最底层的activity之外的所有activity全部清除掉。这些功能或更多的功能,都可以通过manifest文件中设置<activity>元素的属性,或者是在启动activity时配置intent的flag来实现。

在<activity>属性中,有以下几个属性是可以使用的:

  • taskAffinity
  • launchMode

  • allowTaskReparenting
  • clearTaskOnLaunch
  • alwaysRetainTaskState
  • finishOnTaskLaunch

而在Intent当中,有以下几个flag是比较常用的:

  • FLAG_ACTIVITY_NEW_TASK
  • FLAG_ACTIVITY_CLEAR_TOP
  • FLAG_ACTIVITY_SINGLE_TOP

如何通过manifest参数,以及Intent flag来改变Activity在任务中的默认行为。

定义启动模式

启动模式允许你定义如何将一个activity的实例和当前的任务相关联,你可以通过以下两种不同的方式来定义启动模式

1.使用manifest文件

当你在manifest文件中声明一个activity的时候,你可以指定这个activity在启动的时候如何与任务关联

2.使用 intent flag

当你调用startActivity方法时,你可以在intent中加入一个flag,从而指定新启动的activity改如何与当前任务进行关联

如果在manifest中与intent中同时定义,那么在intent中定义将覆盖在manifest中定义。

有些启动模式在manifest中定义,但是在intent中指定不了。同样,有些启动模式在intent中指定,但是在manifest中指定不了

使用manifest文件

当在manifest文件中定义activity的时候,你可以通过<activity>元素的launchMode属性来指定如何与任务相关联launchMode属性一共有以下四种可选参数:

“standard”(默认启动模式)

standard 是默认的启动模式,即如果不指定launchMode属性,则会默认使用这种启动模式,这种启动模式表示每次启动该activity时都会创建一个新实例,声明成这种启动模式的activity可以被实例化多次,一个任务当中也可以存在多个这种activity实例

“singleTop”

singleTop 这种启动模式表示,如果要启动的这个activity在当前任务中已经存在,并且处于栈顶位置,那么系统就不会再创建一个该activity的实例。而是调用栈顶activity的onNewIntent()方法,声明成这种启动模式的activity也可以被实例化多次,一个任务中也可以存在多个这个activity的实例。

“singleTask”

singleTask这种启动模式表示,系统会创建一个新的任务,并将启动的activity放入到这个新任务的栈底位置,但是现有任务当中已经存在一个该activity的实例了,那么系统就不会在创建一次它的实例,而是会直接调用它的onNewIntent()方法,而声明成这种启动模式的activity,在同一个任务当中只会存在一个实例,“注意这里我们所说的启动activity,都指的是启动其他应用程序的activity”,因为“singleTask”模式在默认情况下只有启动其他应用程序的activity才会创建一个新的任务,启动自己应用程序的Activity还是使用相同的任务。

“singleInstance”

“singleInstance” 这种启动模式表示,系统不会再向声明成“singleInstence”的activity任务中添加其他activity,也就是说,这种Activity所在的任务中始终只会有一个Activity,通过这个Activity再打开的其它Activity也会被放入到别的任务当中。

使用Intent flag

除了使用manifest文件之外,你也可以再调用startActivity()方法的时候,为Intent加入一个flag来改变activity与任务之间的关联方式 。

FLAG_ACTIVITY_NEW_TASK

设置这个flag,新启动的activity就会被放置到一个新的任务当中(与"singleTask"有点类似,但不完全一样)当然这里讨论的还是启动其他应用程序的activity。这个flag的作用通常是模拟一种Launcher的行为,即列出一推可以启动的东西,但启动的每一个Activity都是在运行在自己独立的任务当中的。

FLAG_ACTIVITY_SINGLE_TOP

设置了这个flag,如果要启动的Activity在当前任务中已经存在了,并且还处于栈顶的位置,那么就不会再次创建这个Activity的实例,而是直接调用它的onNewIntent()方法。这种flag和在launchMode中指定"singleTop"模式所实现的效果是一样的。

FLAG_ACTIVITY_CLEAR_TOP

设置了这个flag,如果要启动的Activity在当前任务中已经存在了,就不会再次创建这个Activity的实例,而是会把这个Activity之上的所有Activity全部关闭掉。比如说,一个任务当中有A、B、C、D四个Activity,然后D调用了startActivity()方法来启动B,并将flag指定成FLAG_ACTIVITY_CLEAR_TOP,那么此时C和D就会被关闭掉,现在返回栈中就只剩下A和B了。

FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK结合在一起使用也会有比较好的效果,比如可以将一个后台运行的任务切换到前台,并把目标Activity之上的其它Activity全部关闭掉。这个功能在某些情况下非常有用,比如说从通知栏启动Activity的时候

处理affinity

affinity可以用于指定一个Activity更加愿意依附于哪一个任务,在默认情况下,同一个应用程序中的所有Activity都具有相同的affinity,所以,这些Activity都更加倾向于运行在相同的任务当中。当然了,你也可以去改变每个Activity的affinity值,通过<activity>元素的taskAffinity属性就可以实现了。


taskAffinity属性接收一个字符串参数,你可以指定成任意的值(经我测试字符串中至少要包含一个.),但必须不能和应用程序的包名相同,因为系统会使用包名来作为默认的affinity值。


affinity主要有以下两种应用场景:

  • 当调用startActivity()方法来启动一个Activity时,默认是将它放入到当前的任务当中。但是,如果在Intent中加入了一个FLAG_ACTIVITY_NEW_TASK flag的话(或者该Activity在manifest文件中声明的启动模式是"singleTask"),系统就会尝试为这个Activity单独创建一个任务。但是规则并不是只有这么简单,系统会去检测要启动的这个Activity的affinity和当前任务的affinity是否相同,如果相同的话就会把它放入到现有任务当中,如果不同则会去创建一个新的任务。而同一个程序中所有Activity的affinity默认都是相同的,这也是前面为什么说,同一个应用程序中即使声明成"singleTask",也不会为这个Activity再去创建一个新的任务了。
  • 当把Activity的allowTaskReparenting属性设置成true时,Activity就拥有了一个转移所在任务的能力。具体点来说,就是一个Activity现在是处于某个任务当中的,但是它与另外一个任务具有相同的affinity值,那么当另外这个任务切换到前台的时候,该Activity就可以转移到现在的这个任务当中。
    那还是举一个形象点的例子吧,比如有一个天气预报程序,它有一个Activity是专门用于显示天气信息的,这个Activity和该天气预报程序的所有其它Activity具体相同的affinity值,并且还将allowTaskReparenting属性设置成true了。这个时候,你自己的应用程序通过Intent去启动了这个用于显示天气信息的Activity,那么此时这个Activity应该是和你的应用程序是在同一个任务当中的。但是当把天气预报程序切换到前台的时候,这个Activity又会被转移到天气预报程序的任务当中,并显示出来,因为它们拥有相同的affinity值,并且将allowTaskReparenting属性设置成了true。

清空返回栈


如何用户将任务切换到后台之后过了很长一段时间,系统会将这个任务中除了最底层的那个Activity之外的其它所有Activity全部清除掉。当用户重新回到这个任务的时候,最底层的那个Activity将得到恢复。这个是系统默认的行为,因为既然过了这么长的一段时间,用户很有可能早就忘记了当时正在做什么,那么重新回到这个任务的时候,基本上应该是要去做点新的事情了。


当然,既然说是默认的行为,那就说明我们肯定是有办法来改变的,在<activity>元素中设置以下几种属性就可以改变系统这一默认行为:


alwaysRetainTaskState

如果将最底层的那个Activity的这个属性设置为true,那么上面所描述的默认行为就将不会发生,任务中所有的Activity即使过了很长一段时间之后仍然会被继续保留。


clearTaskOnLaunch

如果将最底层的那个Activity的这个属性设置为true,那么只要用户离开了当前任务,再次返回的时候就会将最底层Activity之上的所有其它Activity全部清除掉。简单来讲,就是一种和alwaysRetainTaskState完全相反的工作模式,它保证每次返回任务的时候都会是一种初始化状态,即使用户仅仅离开了很短的一段时间。


finishOnTaskLaunch

这个属性和clearTaskOnLaunch是比较类似的,不过它不是作用于整个任务上的,而是作用于单个Activity上。如果某个Activity将这个属性设置成true,那么用户一旦离开了当前任务,再次返回时这个Activity就会被清除掉。


附:

https://zhuanlan.zhihu.com/p/23704495

感谢楼主无私的奉献!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值