Activity的启动模式详解

以下内容摘抄自作者:任玉刚所著的《Android开发艺术探索》

Activity的LaunchMode

在默认情况下,当我们多次启动同一个Activity的时候,系统会多次创建实例并把它们一一放入任务栈中,当我们点击back键时会将Activity一一回退。任务栈是“后进先出”的栈结构,每按一次back键,就会有一个Activity出栈,直到栈空为止,当栈中无任何Activity时,系统就会回收这个栈。

目前Activity有4种启动模式:

  • standard 标准模式
    这是系统的默认模式,每次启动一个Activity,就会重新创建一个实例,不管这个实例是否已经存在。一个任务栈中有多个实例,一个实例也可以有多个任务栈。谁启动的这个Activity,哪么这个Activity就会在谁的栈中。
    注意:当我们用getApplicationContext()去启动standard模式的Activity时就会报错,报错信息如下:
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
getApplicationContext().startActivity(intent);
android.util.AndroidRuntimeException: 
Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. 
Is this really what you want?

这是因为standard模式的Activity会默认进入启动它的Activity所属的栈中,但是由于非Activity类型的Context(如ApplicationContext)并没有所谓的任务栈,所导致了以上报错。解决方法是为待启动的Activity指定标记位:FLAG_ACTIVITY_NEW_TASK,这样启动的时候会为它创建一个新的任务栈。在这个时候,被启动的Activity实际上已变为被SingleTask模式启动,即在新的任务栈中,创建新的实例。设定标记位代码如下:

Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
  • singleTop 栈顶复用模式
    在这种模式下,如果想要新打开的Activity位于栈顶,那么此Activity将不会被重建,同事它的onNewIntent方法会被回调,通过此方法参数我们可以取出当前请求的信息。需要注意:由于不会被重新创建,只是将后台变为前台,所以onCreate()和onStart()方法不会被调用。相反,当此Activity虽然栈内已被创建,但不在栈顶,此时的Activity仍会被重新创建。

  • singleTask 栈内复用模式
    这其实是一种单例模式,只要Activity在被启动栈内存在,那么多次启动此Activity都不会被重新创建实例,会将已存在的实例切换到栈顶。和singleTop一样,系统也会回到onNewIntent()方法。
    需要注意的是,singleTask具有clearTop效果,会导致该Activity上的所有其它实例全部出栈,比如栈内依次存在ABCD四个Activity,此时DActivity处于栈顶,当启动AActivity时,BCD将被弹出,栈内只留下了AActivity。

  • singleInstanc 单实例模式
    这是一种加强版的singleTask模式,他除了具有singleTask的所有特性之外,需要注意,具有此模式的Activity会单独被存在一个任务栈中,复用时不会再创建任何该Activity实例,除非这个单独的任务栈被系统销毁。

指定启动模式的方法

一共有两种方法

  • 第一种 通过AndroidManifest来指定启动模式
    添加属性:android:launchMode
<activity
  android:name=".MainActivity"
  android:configChanges="orientation|screenSize"
  android:launchMode="singleTask">
  • 第二种 通过在代码中,向Intent添加标志位来指定启动模式:
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
getApplicationContext().startActivity(intent);

这两种启动方法是有区别的。
首先,第二种优先级是要大于第一种的,当两种方式都存在时,以第二种为准。
其次,两种方法在限定范围上有所不同。第一种方法无法为Activity直接设定FLAG_ACTIVITY_CLEAR_TOP标识,第二种方法无法为Activity指定singleInstance模式。

特殊情况

介绍特殊情况时,需要先了解一个参数:TaskAffinity,可以翻译为任务相关性。这个参数标识了一个Activity所需要的任务栈的名字,默认情况下,所有的Activity所需的任务栈同为任务栈的包名,如果想为每个Activity设置单独的TaskAffinity属性,可进行通过添加属性:android:taskAffinity设置,如下:

<activity
  android:name=".MainActivity3"
  android:launchMode="singleTask"
  android:taskAffinity="com.example.test1">

注意:属性内为字符串格式,不能与包名重复,否则相当于没有指定,并且必须包含包名分隔符“.”。
TaskAffinity属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,在其它情况下则没有意义。
另外任务栈分为前台栈和后台栈,用户可以通过切换,将后台栈切换到前台栈。

当TaskAffinity与singleTask模式配对使用时,它是具有该模式的Activity的目前任务栈的名字的,待启动的Activity会运行在和TaskAffinity相同的任务栈中。

当TaskAffinity和allowTaskReparenting一起使用时,会产生特殊的效果。假如B应用的BActivity设置该属性为true时,当在A应用调用了B应用的BActvity后,点击Home,然后进入B应用,B应用会直接打开BActivity,而不会打开首页。 也就是说,在B被打开的时候,BActivity会从A应用的任务栈中回到B应用的任务栈。例如,在某app中通过分享的链接打开了拼dd的某一商品页面,此时按home键返回桌面,这是后再去点pdd,此时pdd会直接打开这个商品界面,而不是首页的商品列表。

接下来说明两种情况:
A、B为包名栈中的Activity,B位于栈顶。C、D为添加了TaskAffinity的自定义栈,自定义栈内顺序为DC,D位于栈顶。

  1. 在B中请求启动D,整个后台任务栈就会被切换成前台,运行结果如下图所示
    B请求D
  2. 在B中请求启动C,运行结果如下:
    B请求C

举例

当前有三个Activity、分别是A、B、C,A的启动模式为系统默认,B和C分别设置为singleTask启动模式,并且B和C的TaskAffinity值为区别于包名的自定义字符串。假设经历以下场景:

  1. A启动了B
  2. B启动了C
  3. C启动了A
  4. A再启动了B

问:最后在B中点击back返回键会返回哪个页面?继续再点击一次呢?
答:第一次点击back返回键会返回A界面,第二次点击back返回的会是桌面。

思路解答:A启动B之后,B会新创建一个任务栈,B创建C后,C也会加入到新创建的任务栈中,C启动A,但A并不在当前任务栈中,所以会在新任务栈创建一个A,此时新任务栈中的顺序为BCA,而一开始的A在位于后台的包名任务栈中,此当前新任务栈中的A又创建B时,由于B的启动模式是singleTask,所以会直接调起到栈顶,但是singleTask会有clearTop效果,会导致在它上面的CA两个实例被弹出,所以最后在B中返回时,会调起后台的包名任务栈A,最后再点击一次返回时,会直接返回到桌面。

以上就是Activity的四种启动模式,下一篇介绍Activity的标记位Flags。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

建洋你是最菜的

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

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

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

打赏作者

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

抵扣说明:

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

余额充值