Activity的四种启动模式

一,为什么要有启动模式?

默认情况下,我们多次打开同一个Activity时,都会创建多个实例并将它们一一放在任务栈中,我们点击back键,会发现这些Activity会一一回退。任务栈是一种“后进先出”的栈结构,每点击一下back键,就会有一个Activity出栈,直到栈空为止,那么系统就会回收这个任务栈。
但是如果多次打开同一个activity,就创建多个实例的话,岂不是太。傻也好,浪费也好,没用也好。反正就是不爽。特别是在一些使用场景下,用户体验很不好的说。所以google大boss为了改善这个默认的行为,就提出了四种启动模式的解决方案。。。

二,四种启动模式介绍
目前四种启动模式主要有:standard、singleTop、singleTask、singleInstance。

  • standard
    标准模式,也是系统的默认模式,每启动一个Activity就会创建一个新的实例(不管这个实例是否存在)并压入栈中。此模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。比如在A页面中启动了B页面,B的启动模式是standard,那么B页面就会进入A页面所在的任务栈中。但是我们用ApplicationContext去启动standard模式的页面时,会报错,比如以下代码去打开B页面:
Intent intent = new Intent(getApplicationContext(), LunchBActivity.class);
getApplicationContext().startActivity(intent);

然后我们就会收到以下错误:
这里写图片描述
这是为啥呢?
因为上面我们说了,谁启动了B页面,那么B页面就会运行在启动它的那个页面的任务栈中,ApplicationContext是非Activity的Context,它没有所谓的任务栈,所以就需要我们在启动的时候给它添加一个标记位FLAG_ACTIVITY_NEW_TASK,为它创建一个新的任务栈,用于存放待启动Activity的实例,其实,此时这个待启动的Activity是以singleTask的模式启动的,后面可以体会一下的。

  • singleTop
    栈顶复用模式。如果A页面已经位于栈顶,那么再次打开A页面时,就不会创建新的实例了。而是直接复用已有的实例,但是会回调A页面的onNewIntent方法,通过此方法我们可以获取最新的请求信息。此时的A页面生命周期执行过程为onPause –> onNewIntent –> onResume。需要特别注意的是A页面的onCreate和onStart方法没有被调用哦。。。


    但是如果A页面已经有实例存在但是不位于栈顶。那么就会重新创建一个A实例。
    比如任务栈中已经有ABC页面的实例,B和C页面的启动模式都是singleTop。从A中打开C页面,那么此时的 栈内实例还是ABC。如果从A中打开B页面,那么此时栈内的实例是ABCB。

  • singleTask
    栈内复用模式。单实例模式。如果一个栈内已经存在A页面的实例,那么无论启动A页面多少次,都不会再创建新的A实例。并且会回调A页面的onNewIntent方法。
    比如:
    已有任务栈S1,S1内已有ABC页面,这时需要启动具有singleTask模式的D页面,
    分为以下几种情况:
    1) 系统会寻找是否有符合D页面需求的任务栈。如果没有,则创建任务栈S2,并创建D的实例,压入S2栈内。
    2)如果S1符合D页面的任务栈要求,则会在S1中寻找是否含有D的实例,如果没有D的实例,则创建D的实例并压入S1栈内,此时S1栈中的实例为ABCD。
    3)如果S1符合D页面的任务栈要求,并且S1中已经含有D页面的实例;分两种情况:
    其一栈内的顺序是ABCD,D位于栈顶,则此时不会创建D的实例,会直接复用D实例,并回调D的onNewIntent方法。
    其二栈内的顺序是ADBC,D不位于栈顶,则系统会将D 切换到栈顶直接复用,并调用D的onNewIntent方法。但是由于singleTask默认具有clearTop的效果,会导致栈内所有D上面的Activity实例全部出栈,于是最后S1栈内的实例只剩下了AD。
    singleTask模式的Activity切换到栈顶会导致在它之上的栈内的其他Activity出栈。

  • singleInstance
    单实例模式。除了具有singleTask模式的特点外,还有一个很重要的特点:就是具有此模式的Activity只能单独的位于一个任务栈中。比如A页面是singleInstance模式,当A启动时,系统会为它创建一个新的任务栈,然后A就单独在这个新的任务栈中了。并且由于栈内复用的特性,以后无论启动多少次的A页面,都不会再创建A页面的实例了。除非含有A页面的任务栈被系统销毁了。

三、如何设置Activity的启动模式
第一种方式是在AndroidMenifest.xml为Activity指定启动模式:
这里写图片描述
第二种方式是在代码中指定:
这里写图片描述

优先级上:第二种的优先级高于第一种,当两者都同时存在时,以第二种为准。
限定范围上也有所区别:
第一种无法为Activity设定FLAG_ACTIVITY_CLEAR_TOP标识。
第二种无法为Activity指定singleInstance模式。

四、指定独有的任务栈
任务栈分为前台任务栈和后台任务栈。
后台任务栈中的Activity处于暂停状态。
TaskAffinity:相关性,标识了一个Activity所需要的任务栈的名字,默认情况下,
所有Activity所需的任务栈的名字为应用的包名,我们可以单独为某个Activity指定TaskAffinity,但是这个属性值不能和应用的包名相同,否则就相当于没有指定。
TaskAffinity属性主要是和singleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下,没有任何意义。
当TaskAffinity和singleTask配对使用时,它是具有该模式的Activity的目前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值