LaunchMode启动模式终结篇

我们在最开始学习Android的时候 就老是听到四个启动模式 面试的时候也是经常被问到四种启动模式是什么 但是却很少深入的真正的了解过 直到今天看到了扔物线的视频 我会了

因为该文是纯文字 所以有些枯燥 但是相信我 仔细读完 写一个Demo 你一定会有收获!!!

App切换

我们首先需要明确一个知识点 Activity是一个可以跨进程跨应用的组件 然后我们根据四种不同的启动模式 慢慢分析理解一下

Task

Task是用于存放Activity的
每个Task都有一个TaskAffinity 默认会取第一个进栈Actity的TaskAffinity
而Activity默认会取Application的TaskAffinity

Standard

比如说 我们在App A里面 加载了App B的Activity(Standard) 那么这个Activity会直接放进App A的Task里 而不会对B有什么影响

SingleTask

先总结一下 SingleTask 具有特性是Activity对应的Task内只能有一个当前Activity实例

举个例子 当我们从微信里发送一个手机号给我们的好友 然后长按这条消息 点击拨打
我们观察一下跳转动画 发现并不是Activity之间的跳转动画 而是App之间的跳转动画

其实上面这个操作流程如下:

  1. 判断拨打电话Activity(后面简称CallActivity) 是否存在
    如果存在则直接将CallActivity的Task压入wechatTask中 并将CallActivity之上的所有Activity出栈 并且不会创建CallActivity的OnCreate方法 取代会调用onNewIntent方法 并且会触发ClearTop的效果
  2. 如果不存在 则新建CallActivity 然后创建对应CallTask 并放入CallTask
  3. 将CallTask压入WeChatTask
  4. 所以我们点击返回按钮 会发现先回退CallTask里面的Activity 然后再退到WeChat的Task

大家可以先使用 然后再对比文章阅读 直接看可能没有动画来的直观

但是 我们在上面的第三步完成之后 这时候先不按返回键 而是按Home键或者菜单键 然后再点击CallActivity 我们会发现 一直点击返回按钮 会回到桌面 而不是回到WeChat的Task了

这是因为系统当回到桌面时 会将各Task进行分离

系统虽然声明为SingleTask 其实是对Activity的修饰 保证了全局只有一个这个Activity实例

TaskReparting

这个实现的效果和SingleTask差不多 举个例子 当我们从CallTask启动EmailActivity(TaskReparting = true) 然后回到桌面 再进去CallTask 会发现EmailActivity已经消失 打开邮件应用 EmailActivity会防止在EmailTask最顶部 这就是TaskReparting 当TaskA使用的时候 会存在于TaskA中 当不使用时 会回到自身的Task中

但是看了扔物线的视频 指出了TaskReparting在Andorid 9.0和10.0是存在Bug的 使用这个属性的同学 请做好测试

SingleInstance

SingleInstance 和SingleTask有点相似 SingleTask强调一个Activity只能在这个Task里出现一个实例 而SingleInstance更为霸道 一个activity在Task里只能出现一次 并且这个Task里只能有这个Activity

SingleInstance和SingleTask在实际的操作中区别如下

  • 当我们的应用分别启动一个SingleInstanceActivty和SingleTaskActivity 当我们点击返回时

    • SingleInstanceActivty会直接返回到当前App 因为SingleInstance中的Task只能存在一个Activity
    • 而SingleTaskActivity会现在SingleTask进行回退 回退完成才会切换到当前应用Task
  • 第二个区别就是 分别启动一个SingleInstanceActivty和SingleTaskActivity之后 我们点击Home键 然后分别启动SingleInstanceActivty和SingleTaskActivity对应的App

    • SingleTask App会看到这个Activity依然在栈顶
    • 而SingleInstanceActivty会发现在任务列表已经不见了 其实并不是被杀死了 只是SingleInstanceTask被切换到后台了

总结一下 感觉SingleTask强调唯一性 而SingleInstance更强调独占性

TaskAffinity

TaskAffinity我感觉是最绕的一个 所以下面会举例来说明

先解释一下TaskAffinity 我们上面讲过 每个Activity默认都会取Application的TaskAffinity 而Application默认会取包名 所以我们不修改Activity的TaskAffinity 那么Activity的TaskAffinity默认就是包名

下面我们分别对各种情况作出说明


ActivityA对应的TaskAffinity为Affinity_A launchMode为Standard

ActivityB对应的TaskAffinity为Affinity_B launchMode为Standard

ActivityC对应的TaskAffinity为Affinity_C launchMode为Standard

当我们点击App图标 启动ActivityA时 会创建Task, Task的TaskAffinity会是Affinity_A 然后再启动ActivityB会不会检查Affinity_B 而是直接入栈


ActivityA对应的TaskAffinity为Affinity_A launchMode为Standard

ActivityB对应的TaskAffinity为Affinity_B launchMode为SingleTask

ActivityC对应的TaskAffinity为Affinity_C launchMode为Standard

当我们点击App图标 启动ActivityA时 会创建Task, Task的TaskAffinity会是Affinity_A 然后再启动ActivityB 因为ActivityB的启动模式为SingleTask 所以会判断ActivityB的TaskAffinity
分为以下两种情况

  • TaskAffinity为Affinity_A 因为TaskAffinity一样 所以会直接将ActivityB入栈

  • TaskAffinity为Affinity_B 因为TaskAffinity不一样 所以会创建TaskB 并且将Activity_B入栈(Task_B的TaskAffinity为AffinityB)

然后再启动C 因为我们之前说过 因为C的launchMode为Standard 所以不会检查Activity_C的任务栈 直接入栈


ActivityA对应的TaskAffinity为Affinity_A launchMode为Standard

ActivityB对应的TaskAffinity为Affinity_B launchMode为SingleInstance

ActivityC对应的TaskAffinity为Affinity_C或者Affinity_A launchMode为Standard

当我们点击App图标 启动ActivityA时 会创建Task, Task的TaskAffinity会是Affinity_A 然后再启动ActivityB 因为ActivityB的启动模式为SingleInstance 所以会创建一个新的Task(AffinityB) 并且独占当前Task 然后创建C的时候
需要分为以下两种情况

  • Affinity_A 因为SingleInstance的缘故 所以没办法进入TaskB 但是Affinity_A已经创建 所以会将Affinity_A切换到前台 并且将ActivityC压入TaskA

  • Affinity_C 因为SingleInstance的缘故 所以没办法进入TaskB 并且当前任务栈是不存在的 所以这时候相当于和我们在桌面点击App图标一样 会创建一个新的Task(Affinity_C)

SingleTop

和Standard基本一样 启动时不考虑TaskAffinity 区别是启动时 如果当前Activity已经存在栈顶 那么不会调用onCreate方法 而是会调用onNewIntent方法

总结

Standard和SingleTop 更多用于App内部应用开发
SingleInstance 用于开放给其他App使用
SingleTask 内部交互和外部交互都用的上

大家还有什么不明白和不理解的 欢迎留言交流