Android启动模式的抽丝剥茧之旅

本文详细解析了Android中Activity的四种启动模式(standard、singleTop、singleTask、singleInstance)及其与Task的关系,包括回退栈Task的工作原理、taskAffinity属性的影响,以及allowTaskReparenting属性在不同版本上的表现。理解这些概念对于优化App的用户体验和流程控制至关重要。

前言

作为Android开发者,工作中不可避免会使用到Android的启动模式,一般App都有若干个Activity,并使用栈结构Task(后进先出)维护App的Activity,而启动模式则是针对Task如何管理Activity的手段。
当用户在使用App时,点击最近任务键切换到别的App,或者点击Home键返回桌面之后再次进入App,App的栈结构会不会发生改变?当重新启动一个栈内已存在的Activity时会重新走onCreate()方法还是会走别的方法?这些问题都需要我们对Activity的启动模式以及回退栈Task等有一个比较清晰地了解之后才能更好的进行App开发。

1. 回退栈Task

当点击桌面图标时,App启动的默认Activity是我们在AndroidManifest中配置了intent-filter标签且其action为MAIN,category为LAUNCHER的Activity,并且会被放入系统新建的Task栈中,其根据顺序记录了用户打开的每个Activity,当用户点击回退按钮时,依次倒序的关闭Activity,当Task中的最后一个Activity也被关闭之后,此Task的使命也随之结束,但是在点击最近任务键时显示的最近任务依然会有当前App的Task记录的界面的图像,只不过此时点击时会重新启动新的Task。

2. 启动模式

Activity是一个可以跨进程跨应用的组件,比如我们在使用美团点外卖时,我们可能会用微信或者支付宝进行订单支付,当我们进入支付页面的时候,界面切换效果为应用内切换动画,我们点击最近任务键查看最近任务也会发现支付页面对应的Task是美团App的,而此时我们点击Home键返回到桌面,再点击微信或者支付宝,其进入的是微信或者支付宝的首页,并不是当前的支付页面;再比如我们在微信中点击手机号时会跳转到拨打电话界面,界面切换效果为应用间切换动画,此时我们点击最近任务键也会发现微信和拨打电话的Task都会显示在最近任务列表中。这些都是不同启动模式的展现效果。

2.1 standard模式

standard对应的是Activity的默认启动模式,默认会把Activity创建之后加入到当前Task栈,该模式启动的Activity可以被多次实例化,也就是说不管是不是同一个Task都可以存在多个此Activity的实例。
standard多个实例

2.2 singleTop模式

该模式和standard一样,默认也会把Activity创建之后加入到当前Task栈,只不过如果启动的Activity的实例已经存在于栈顶就不再进行创建新的实例,而是重用当前的实例,并且调用这个栈顶的Activity的onNewIntent(),singleTop虽然名字上有single,但它在关系上和默认的standard其实更近一些。
栈顶一个实例

2.3 singleTask模式

singleTask模式下的Activity在Task栈中只会存在一个实例并且全局只会存在一个此Activity的实例,也就是说设置为singleTask的activity在被别的App启动的时候不会在别的App的Task中创建,也不会进入别的App的Task里,而是会创建并压入属于自己的回退栈Task里面,如果这个Task中已经有该Activity的实例,会将Task中的盖在此Activity上面的Activity进行出栈操作,然后将这整个Task一起拿过来压在启动它的App的Task的上面,并且Activity的入场动画也是应用间跳转动画,而不是应用内Activity的跳转动画,也就是说singleTask既保证了只有一个Task里面有这个Activity又保证了这个Task里面最多只有一个这个Activity,所以singleTask限制了在全局只有一个对象。
多个Task一个实例

设置singleTask的Activity和启动它的App无关,会放在自己的Task里,如果此时逐次按返回键,会发现首先会逐步出栈设置为singleTask模式的Activity所在的Task里面的Activity,当此Task里面的Activity都出栈之后才会回到打开它的App的Task,而且此刻又变成了应用间切换的动画(准确地说是Task间切换动画)。
Task间退出

可以看出,后面打开的App中的Activity都出栈之后并没有回到桌面,反而回到了前一个App的Task,不同的Task好像叠在了一起,但是如果在跳转到了别的设置为singleTask的Activity的App之后,此时如果点击最近任务键或者点击Home键,然后再回到App逐步点击返回就会发现前一个Task中的Activity全部出栈之后不会再回到启动它的App,也就是说App在进入后台的那一刻,叠在一起的Task又被拆开了。

2.4 singleInstance模式

singleInstance的属性和singleTask几乎是一样的,只不过它多了一个更严格的限制,其要求所在的Task里只有这么一个Activity,也就是说设置了singleInstance模式的activity在启动时会单独创建一个Task并把这个Activity入栈,并且该Task只会维护这个Activity,如果之前已经启动过这个Activity了,那就会像singleTask一样,直接复用这个Activity,调用它的onNewIntent(),入场动画也是Task间切换动画。
singleInstance模式,全局单个实例

可以看到,当从一个App启动新的App的singleInstance模式的Activity后再点击返回键时,跟singleTask类似,singleInstance的Task因为只有一个Activity,所以会直接回到下面的App的Task,出场动画也是切换Task的动画。
回到后台拆分Task

如上图,如果先点击Home键再又从最近任务列表又返回来,此时因为叠加的Task在回到后台时已经被拆分,所以如果再点击返回键的话就不会回到上一个App的Task而是直接回到桌面。
Task叠加并且先将最上面Task内部Activity依次出栈,再回到下面的Task

可以看到,singleInstance模式的Activity里如果又启动了新的Activity的话新的Activity并不会进入当前的Task,而是会进入别的Task里,然后系统会将这个Task完整的叠加在singleInstance模式的Task的上面,当按返回键时,会先将上面的Task里的所有的Activity进行出栈之后才会回到当前的singleInstance模式的Activity,并且出场动画为Task切换动画。
回到桌面导致singleInstance消失

如上图,其他模式的Activity启动singleInstance模式的Activity之后如果直接点击Home键再返回App会发现singleInstance模式的Activity不见了,变成了上一个Activity,看起来好像被系统干掉了,但是其并没有被干掉,只是在最近任务列表看不见了,当再次启动它时就会跑到前台,并调用onNewIntent()方法。

为什么会在最近任务列表消失了?这是因为singleInstance模式的Task的taskAffinity和默认的Task的taskAffinity冲突了。

3. taskAffinity

在Android中,一个App默认只有一个Task可以显示在最近任务列表里,其是通过taskAffinity进行区分的,AndroidManifest中可以对每个Activity进行taskAffinity配置,如果不配置默认则是application的taskAffinity,而application的taskAffinity默认为App的包名。然后Task记录第一个入栈的Activity的taskAffinity,后面入栈的Activity的taskAffinity就会被忽略,但是如果新的Activity是singleTask模式,系统则会校验该Activity的taskAffinity和Task记录的taskAffinity是否一致,一致则入栈该Task,否则此Activity会入栈taskAffinity相同的Task或者如果没有相同的就创建一个新的Task。
AndroidManifest配置信息
配置了taskAffinity和默认的区别

默认情况下singleTask模式的Activity如果是在自己的App中被启动则会进入当前App的Task,并且进入动画为应用内切换动画,如果是在别的App中被启动,则会发生Task切换,但是如果给这个Activity设置了taskAffinity,哪怕是同一个App,这个Activity也会被放进别的Task,如果taskAffinity和别的App的taskAffinity一样,则还会进入别的App的Task,而且点击最近任务键查看最近任务列表也会发现都会被罗列出来,taskAffinity如果一致则不会。如果taskAffinity一致但是为singleInstance模式,最近任务列表则会出现被顶替现象。

4. allowTaskReparenting

standard模式和singleTop模式下的Activity的实例对象创建之后只会在当前的Task里面,不会在多个Task之间切换,但是我们可以在AndroidManifest中通过将allowTaskReparenting属性设置为true实现Activity在Task间跳转效果。
standard模式的allowTaskReparenting演示

如上图可见,当在其他App启动该Activity之后点击Home键,再启动该Activity所在的原本的App,会发现Activity回到了原本的App,有点类似于singleTask,并且没有singleTask那种应用间切换的入场动画效果。
测试直接通过点击最近任务键切换

然而,直接通过点击最近任务键切换回此Activity所在的App不会使其回到属于他的App中。而且通过测试发现在Android9和10上面这个属性没有效果,别的版本又可以,所以这个属性还是不用为好。

5. 总结

  1. 默认standard是将Activity直接入栈当前的Task,交互动画为应用内切换动画,不管是相同Task还是多个App的Task,该模式Activity可以被多次实例化,并且和taskAffinity无关。
  2. singleTop模式和standard模式几乎一样,只不过多了一条限制,如果启动的Activity的实例已经存在于栈顶就不再进行创建新的实例,而是重用当前的实例,并且调用这个栈顶的Activity的onNewIntent()。
  3. singleTask模式的Activity只存在于一个Task中,并且该Task只会存在一个当前Activity的实例,如果再次启动此Activity,会将其Task上面的Activity出栈,并调用此Activity的onNewIntent(),其他App启动此Activity会将该Activity所在的Task叠在启动它的App的上面,按返回键时会先将此Activity所在的Task全部退出才会返回上一个App,此Activity默认是和它所在的App的包名相同的Task中,可以通过修改taskAffinity属性来改变Activity归属于哪个Task。
  4. singleInstance和singleTask也很相似,只不过singleInstance独占了一个Task,不管此模式的Activity的taskAffinity和别的是否一致,都会独占一个Task,如果taskAffinity和别的Task一样,会在最近任务列表中顶替掉别的Task显示在任务列表中(但是别的Task依然存在,当回到桌面或者此Activity销毁后前面的Task就会显示出来;如果点击最近任务键再回到App,然后点击返回键会直接回到桌面,不会回到上一个Task的Activity),singleTask强调唯一性,singleInstance除了唯一性还强调独占性。
  5. allowTaskReparenting可以让standard和singleTop实现类似singleTask的效果,并且不会出现夸张的应用间切换动画,但是该属性在Android9和10无效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Payne_guo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值