Android 的四种启动模式,分别是 standardsingleTopsingleTasksingleInstance。四种启动模式都跟栈有关。

    这里简单概况自己觉得比较容易一下子看懂的说法。

    当没有在 AndroidManifest.xml 里为 <activity> 配置 android:launchmode 时,所有的 Activity 默认都是以 standard 模式启动的

    预先提醒好,Task 和 栈 是两个概念,最简单粗暴的说:

    1. 栈是你看不见摸不着的,多个栈可以存在于同一个 Task 里;

    2. 另一个 Task 启动后,你能在最近任务里看到它。

    结尾有一个太长不看(虽然并不长)的总结。

    standard - 默认模式

    简单的说,就是你每次启动这个 Activity 时,无论情况如何,都会创建一个新的实例。比方说你打开了 MainActivity,这个 Activity 里有一个按钮 StartButton,点击后会完整启动 MainActivity

    此时的栈点击前

    • MainActivity // 原先的
    • ...

    点击后

    • MainActivity // 新的
    • MainActivity // 原先的
    • ...

    即使栈里原本就有 MainActivity,此时还是会创建一个新的 MainActivity 实例,并且按顺序调用 onCreate()onStart()onResume(),与新的完全一样。

    有关 taskAffinity,留到后面讲。

    singleTop - 栈顶复用

    跟 standard 不同,在上面的程序中,如果设置了 singleTop,并且当前 Activity 处于栈顶,在点击 StartButton 后,并不会重新创建实例,而是保留原本的实例(但会调用 onNewIntent()

    也就是这个 Activity 在前台运行时,如果你还想启动这同一个 Activity,则并不会跟 standard 模式一样再创建实例,即并不会调用 onCreate()onStart()

    此时的栈点击前

    • MainActivity // 原先的
    • ...

    点击后

    • MainActivity // 原先的 &“新”的
    • ...

    但是此时会调用 MainActivityonNewIntent() 方法。

    对了,如果前面前提不成立,当前 Activity 不在栈顶呢?那就跟 standard 模式一样重新创建实例,比如:

    此时的栈点击前

    • OtherActivity
    • MainActivity // 原先的
    • ...

    点击后

    • MainActivity // 新的
    • OtherActivity
    • MainActivity // 原先的
    • ...

    有关 taskAffinity,留到后面讲。

    singleTask - 栈内复用

    其实看到名字可以以此类推了,singleTask 模式下,只要栈里有 MainActivity,就会直接将 MainActivity 上方的所有 Activity 全部出栈,让 MainActivity 回到栈顶。

    “这个栈里只能容得下一个👴!”

    此时的栈点击前

    • AnotherActivity
    • OtherActivity
    • MainActivity // 原先的
    • ...

    点击后

    • MainActivity // 原先的 &“新”的
    • ...

    MainActivity 上方的两个 Activity 都被出栈了。

    这一部分需要讨论 taskAffinity(终于)

    taskAffinity 也是 <activity> 的一个属性,即 android:taskAffinity。未设置的情况下,其默认值为包名

    是的,如果设置了与包名不一样的 taskAffinity,其对应的 Activity 的 Task 就发生了改变。下面假定 Activity 启动顺序为:

    1. 未设置 taskAffinityOtherActivity(默认 standard 模式)
    2. 设置了 taskAffinityMainActivity(指定 singleTask 模式)
    3. 未设置 taskAffinityAnotherActivity(默认 standard 模式)

    所以:

    1. 在启动了 OtherActivity 后启动 MainActivity,由于 MainActivity 的启动模式是 singleTask,此时 Android 会查找其 taskAffinity。在这里会发现它的 taskAffinity 并非与包名相同,因此会创建一个新的 Task,并将 MainActivity 放入其中(此时 MainActivityOtherActivity 处于不同的 Task 中);
    2. 然后,启动 AnotherActivity。因为 AnotherActivity 使用的是 standard 模式,Android 无需去寻找其 taskAffinity 的值,只要跟着之前的 Activity 就行,因此此时的 AnotherActivity 会进入 MainActivity 所在的栈。

    之前:

    • OtherActivity
    • ...

    之后:

    旧栈

    • OtherActivity
    • ...

    新栈

    • AnotherActivity
    • MainActivity
    • ...

    这里可以看到,设置了 taskAffinityMainActivity 启动后,由于切换到了新栈,启动 AnotherActivity 的话,它不会回到旧栈,而是在新栈中成为栈顶。

    singleInstance - 全局唯一

    跟 singleTask 差不多,但是使用此启动模式创建的 Task,整个 Task 里只有它自己一个。直接上例子可能会好一点。

    我们预先设定 OtherActivity 使用 standard 模式,MainActivity 使用 singleInstance 模式。

    当两者 taskAffinity 相同时

    此时会创建新的 Task 且独一无二,点击启动 MainActivity 前:

    • OtherActivity
    • ...

    点击后:

    原来的 Task

    • OtherActivity
    • ...

    新的 Task

    • MainActivity
    • ...

    但是这里注意,如果我在 MainActivity 里再想启动 AnotherActivity 时:

    原来的 Task

    • AnotherActivity
    • OtherActivity
    • ...

    新的 Task

    • MainActivity
    • ...

    是的,新的 Activity 并不会进入到新的 Task 里, 所以说 singleInstance 创建的 Task 是独一无二的。

    当两者 taskAffinity 不同时

    表现上与 taskAffinity 相同时一致,但是可以在最近任务里看到。

    总结

    简单来说:

    standard

    你想创建新实例就创建吧,随你,叠千层饼都行。

    singleTop

    如果你想启动你面前(栈顶)的 Activity 的话,除了会调用它的 onNewIntent() 外没什么变化。除此之外,跟 standard 一样。

    singleTask

    taskAffinity 相同的时候(不设置的时候也相同),如果之前开过这个 Activity(还在栈里),就直接把它拽到最前面,其他的统统废掉(栈中在它上方的全部出栈)

    taskAffinity 不相同的时候,启动这种 Activity 后,它会脱离于原来的 Task,新开一个,而且新顾客也会跟着它到新的地方去(后续启动的 Activity 会跟随着进入到新的 Task)而且你能在最近任务里看到它有别于原来的 Activity(后台里任务卡片大于一张)

    singleInstance

    taskAffinity 相同的时候(不设置的时候也相同),启动这种 Activity 后,它会脱离于原来的 Task,新开一个,但是新顾客不会跟它走,新顾客还是会回到老的地方去(后续启动的 Activity 会在原来的 Task 中启动)

    taskAffinity 不相同的时候,启动这种 Activity 后,它跟 taskAffinity 相同的时候一样,唯一不同的是你能在最近任务里看到它有别于原来的 Activity(后台里任务卡片大于一张)

    Tips

    • taskAffinity 是否相同会直接影响到后台是否在同一张任务卡片里。

    参考: