Activity launchMode详解

Activity android:launchMode详解

Task

首先介绍 Task 的概念。Task 可以理解为任务栈,用来存放 Activity,按照先进先出的顺序。一个应用可以具有多个 task,一个 task 里面也可以具有多个 Activity。默认的话只有一个任务栈,所有 Activity 都是在这个任务栈中管理,特殊情况下会有多个 task,而这些 task 之间是可以互相切换的(back键或者最近应用列表)。

android:launchMode

先开看一个 Demo。假设有3个 Activity ABC,每个 Activity 上面都有3个按钮启动自己和其它的 Activity(如下图),首先启动的主 Activity 是 A 。下面以这个 Demo 来分析各种 launchMode 的用法。
Activity launchMode详解_第1张图片

  • standard
    standard 是标准的启动模式,默认不写就是 standard。当启动一个 Activity 后,就会在当前栈进行入栈操作。
    先启动主 Activity A,然后单击 Start Activity B 再启动 B,则会再次生成一个 B 的实例并入栈;再单击 Start C 来启动 C 后,生成 C 的实例并入栈;然后单击 Start C,则又生成一个新的 C 的实例入栈;然后单击 Start B 则又启动一个新的 B 并入栈,最后依次单击 back 键,则 Task 里的 Activity 会从上到下依次进行出栈。具体栈的情况如下图:
    Activity launchMode详解_第2张图片

  • singleTop
    singleTop 和 standard 很相似,唯一不同的是如果当前需要启动的 Activity 位于栈顶,则会直接返回栈顶的实例,不在重新生成新的实例,并会执行 onNewIntent 方法。现在设置 A 为 standard,B 和 C 为 singleTop,同样的按照上面的流程走一遍,栈情况如下图:
    Activity launchMode详解_第3张图片
    可以看到第三步 start C 的时候,因为 C 已经位于栈顶,则没生成新的实例,此时会调用 C 里面的 onNewIntent 方法而并不执行 onCreate。而第四步 start B 的时候因为 B 不在栈顶则又生成了一个实例,和 standard 的情况相同。

  • singleTask
    singleTask 和 standard 也类似,不同的是如果栈中已经存在需要启动的 Activity 的实例,则会把它上面的 Activity 全部出栈,并返回当前的实例,而不重新生成新的实例,同时响应 onNewIntent 方法。现在设置 A 为 standard,B 和 C 为 singleTask,流程如下:
    Activity launchMode详解_第4张图片
    第三步 start C 的时候和 singleTop 相同,都是返回已经存在的 C 的 实例并相应 onNewIntent 方法。第四步 start B 的时候,因为 B 已经存在, 则 B 上面 C 出栈,返回 B 并响应 onNewIntent 方法。

  • singleInstance
    singleInstance 跟上面几种有些不同,设为 singleInstance 的 Activity 所处的栈里面只能有它一个 Activity 实例,不允许有其他的 Activity 实例。如果已经存在则返回并响应 onNewIntent,如果不存在则会开一个新的栈并创建一个新的实例入栈。现在设置 A 和 C 为 standard,B 为 singleInstance,则流程如下:
    Activity launchMode详解_第5张图片
    这里第一步 start B 的时候,开了一个新的 Task #2,并且 Task #2 位于前台。第二步 单击 start C 后则 C 又会压入原来的 Task #1 中(此处 C 的栈和taskAffinity设置有关,后面会讲解),此时 Task #1 来到前台。 当第四步 start B 的时候因为 B 已经存在了,则 Task #2 来到前台返回B并相应onNewIntent 方法。第五步 back 的时候, 因为 Task #2 在前台, 所以 B 出栈, Task #2 销毁,Task #1 回到前台, 后面再单击 back 和之前就上面几种就一样了。

android:taskAffinity

taskAffinity 即 task 亲和力,相当于给 task 设置了一个 tag, Activity 启动时会去查找跟它的taskAffinity相同的task,如果找到则入栈,找不到的话则新建一个 task 入栈并设置 affinity,与 singleTask 连用。默认不设置的话 taskAffinity 的值就是包名。当我们看最近程序列表的时候会发现的不同 affinity 的 task。

以下是几个例子来帮助理解 taskAffinity:

  • 设置 Activity如下(假设包名为com.company.demo):
    A: launchMode=standard, taskAffinity不设置(即为包名com.demo)
    B: launchMode=singleTask, taskAffinity=com.demo.b
    C: launchMode=standard, taskAffinity不设置(即为包名com.demo)
    Activity launchMode详解_第6张图片
    由于 B 设置了 taskAffinity 并且 launchMode=singleTask,因此 B 会寻找 affinity 为 com.demo.b 的 task,因为没找到所以新建了个 task 并入栈了。然而启动 C 的时候,C 没设置 taskAffinity,即为默认的包名,按理说应该在 Task #1 中入栈,但为什么跑到 Task #2 中了呢?因为 C 不是 singleTask 的,不管设置没设置 taskAffinity 都会在当前栈中启动(当 B 不为 singleInstance情况下)。

  • 下面来说说当 B 为 singleInstance 的情况。设置 Activity如下(假设包名为com.demo):
    A: launchMode=standard, taskAffinity不设置(即为包名com.demo)
    B: launchMode=singleInstance, taskAffinity=com.demo.b
    C: launchMode=standard, taskAffinity不设置(即为包名com.demo)
    Activity launchMode详解_第7张图片
    由于 B 的 launchMode=singleInstance,所以肯定会创建一个新的 Task,又因为设置了 taskAffinity,所以这个新的 task 的 affinity 为com.demo.b(假如 B 不设置 taskAffinity,那么这个新的 task 的affinity 还是包名com.demo)。启动 C 的时候, 因为 singleInstance 的 Task 只能存在一个实例, 所以 C 启动的时候会根据它的 taskAffinity 来决定进入哪个 task。因为 C 没设置 taskAffinity,即为包名,所以会进入跟 A 相同的 Task #1 中。

    如果 C 设置了 taskAffinity=com.demo.c,则会创建一个新的 task #3,此时 task 情况如图:
    Activity launchMode详解_第8张图片
    假如 C 设置了 taskAffinity=com.demo.b 跟 B 相同会是什么情况呢:
    Activity launchMode详解_第9张图片

总结:

  • 如果 launchMode=singleTask,则会寻找与 taskAffinity 相同的 task 并入栈,没有则创建一个新的 task。

  • 如果 launchMode=standard 或者 singleTop:

    • 若当前 Activity 不是singleInstance,则直接在当前 task 中入栈
    • 若当前 Activity 是 singleInstance,则根据 taskAffinity 来寻找相同的 task 或创建新的
  • 如果 launchMode=singleInstance,这个就不用说了,因为 singleInstance 总是会创建新的 task,设置了 taskAffinity 就是给 task 加个标记罢了。

你可能感兴趣的:(Android基础)