《Android开发艺术探索》读书笔记----第一章:Activity的启动模式

Activity的启动模式

我们知道,在默认的情况下,当我们多次启动同一个Activity的时候,系统会创建多个实例并把它们一一放入到任务栈中,当我们点击back键,这些Activity一一回退。任务栈是先进后出的原则,当栈中没有任何Activity的时候,系统会回收这个任务栈,activity目前有四种启动模式:

  • standard
  • singleTop
  • singTask
  • singleInstance

启动模式详解

  • standard
    标准模式,这是系统默认的模式,每次启动Activity都会重新创建一个新的实例,不管这个实例是否已经存在,这是一种典型的多实例实现,一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。在这种启动模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。比如 Activity A 启动了 Activity B (B是标准模式) 那么B就会进入到A所在的栈中。
    总结:standard模式下,不论是否有相应的实例,都会重新创建一个置于栈顶。

  • 常见问题:
    当我们用 ApplicationContext 去启动 standard 模式的 Activity 时,会报错,这是因为 standard 模式的 Activity 默认进入启动它的 Activity所属的栈中,但是由于非 Activity 类型的 Context (如 ApplicationContext)并没有所谓的栈,所以会报错。解决方法是:为待启动的 Activity 指定 FLAG_ACTIVITY_NEW_NEW_TASK 标记位,这样启动的时候会为他创建一个新的栈,实际上待启动的 Activity 是以SingleTask模式启动的。

  • singleTop
    栈顶复用模式。在这种模式下,如果新的 Activity 已经位于栈顶,那么此 Activity 不会被重建,同时它的 onNewIntent 方法会被回调,通过此方法的参数我们可以取出当前请求的信息。需要注意的是,如果此 Activity 没有被重建,那么它的 onCreate、onStart 不会被系统调用,因为它并没有发生改变。如果栈中有相应的 Activity 的实例,但是不是位于栈顶,那么依然会被重建。假如当前栈内 Activity 情况为: ABCD A位于栈底,D位于栈顶 ,此时启动D,如果D的启动模式为 SingleTop 那么栈内情况为:ABCD 如果D的启动模式为 standard 那么情况为:ABCDD

  • singleTask
    栈内复用模式。这是一种单实例模式,在这种模式下,只要 Activity 的实例在一个栈中存在,那么多次启动此 Activity 不会重新创建实例,和 singleTop 一样,系统会调用 onNewIntent 方法。当一个具有 singleTask 模式的 Activity 请求启动后,比如A,系统会寻找是否存在A想要的任务栈,如果不存在就重新创建一个任务栈,然后创建A的实例放到栈中,如果存在A所需要的任务栈,就要看A是否在栈中有实例存在,如果有实例存在,系统就会把A调入栈顶,并且调用它的 onNewInstance 方法,如果实例不存在就创建A的实例并且把A压入栈中。举例说明:
  • 比如目前任务栈 S1 的情况为 ABC ,这个时候D以 singleTask 的模式请求启动,所需要的任务栈为 S2,那么系统为先创建任务栈 S2并创建D的实例放入 S2中。
  • 假设D所需要的任务栈为S1,而S1中又没有D的实例,此时系统会创建D的实例放入S1中。
  • 若S1中情况为 ADBC,并且D所需要的任务栈为S1,由于S1中存在D的实例,所以不需要重新创建,只需要将D移至栈顶,但是由于任务栈特点的限制,必须移动顺序为CBD,所以此时CB的实例会被移出栈。最终情况为AD。

  • singleInstance
    单实例模式。这是一种加强的 singleTask 模式,它除了具备有singleTask 模式的所有特性外,还加强了一点,就是具有此种模式的 Activity 只能单独的在一个任务栈中,当A启动后,系统会为它新建一个任务栈,然后A独自在这个新的栈中,由于栈内复用的特征,后续的请求均不会创建新的 Activity ,除非这个任务栈被系统销毁。

  • TaskAffinity
    在singleTask 模式中多次提到 Activity 所需要的栈,那么什么是 Activity 所需要的栈呢?这要从一个参数说起:TaskAffinity ,可以翻译为 任务相关性 。这个参数标识了一个 Activity 所需要的任务栈的名字。默认情况下,所有 Activity 所需要的任务栈的名字为 应用的包名,当然也可以为每一个 Activity 指定一个TaskAffinity 的属性值,但是这个值不能和包名相同,否则就相当于没有指定。TaskAffinity 属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有意义。另外,任务栈分为前台任务栈和后台任务栈,后台任务栈的 Activity 位于暂停状态,用户可以通过切换,将后台任务栈再次调到前台。

  • 当TaskAffinity 和singleTask 启动模式配对使用时,它是具有该模式的 Activity的目前任务栈的名字,待启动的 Activity 会运行在名字和 TaskAffinity 相同的任务栈中。
  • 当 TaskAffinity 和allowTaskReparenting 结合的时候,情况比较复杂。当一个应用A启动了B的某个 Activity 后,如果这个 Activity的allowTaskReparenting为true的话,那么B应用被启动后,此 Activity 会直接从应用A的任务栈转移到应用B的任务栈。举例:
  • 有两个应用A和B,A启动了B的一个 Activity C,(C的allowTaskReparenting属性必须为true),然后按Home键回到桌面,再启动B应用(点击B的图标),会发现此时启动的不是B的主Activity,而是重新显示了已经被应用A启动的 Activity C,或者说,C已经从A的任务栈转移到了B的任务栈。可以理解:A启动了C,这个时候C只能运行在A的任务栈中,但是C属于B的应用,正常情况下它的 TaskAffinity 肯定和A的任务栈不同(因为包名不同),所以当B启动后,B会创建自己的任务栈,这时候系统发现C所需要的任务栈已经被创建了,于是把C从A的任务栈中转移过来了。

如何设置 Activity 的启动模式

有两种方法:
- 第一种是在 Manifest文件中设置:

<activity
android:name=".MainActivity"
android:launchMode="singleInstance"/>

  • 第二种是在Intent中设置标志位来指定:

Intent intent=new Intent();
intent.setClass(MainActivity.this,SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);


两种方式的比较:
首先,优先级上 Intent 要高于在Menifest中指定,当两种同时存在时,以 Intent为准。
在范围上有所不同:在Menifest中无法指定 Intent.FLAG_ACTIVITY_CLEAR_TOP 属性,在Intent中无法指定 singleInstance模式。


暂时就这么多,有点晕….

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值