问题
问题描述: 我们的 app 被其他 app 启动进入 MainActivity, 然后 MainActivity 连续调用两次 startActivity 分别启动 IndexActivity 和 CommonActivity, 先启动的 IndexActivity, 然后启动的 CommonActivity, 然后神奇的是屏幕上显示的是 IndexActivity, 按返回关闭 IndexActivity 后才显示 CommonActivity
这个问题是同事在做被第三方 app 打开这个功能时发现的, 他自己写的 demo 测试都是正常的, 移到我们项目上来就不行了, 他对比了下发现是 IndexActivity 的 launchMode 设置的 singleTask, 去掉就是正常的了, 但是这个 singleTask 又是其他功能需要的不能去 (这个功能是我加的), 所以最后反馈到我这了
当时觉得是很神奇但是又不知道为什么, 自己跑了下确实像同事说的去掉 singleTask 就好了, 考虑到启动模式会影响 activity 的任务栈, 想先看一下加了 singleTask 时的任务栈和去掉后的任务栈有什么区别然后就百度了下, 确实可以查看当前的任务栈, adb 命令
adb shell dumpsys activity activities
具体打印出来的信息很多, 这里就不放了, 说一下从里面发现了什么
结果
假定第三方 app 为 App1, 我们的 app 为 App2,App1 的 TestActivity 启动 App2 的 MainActivity, 然后 MainActivity 连续调用两次 startActivity 分别启动 IndexActivity 和 CommonActivity, 先启动的 IndexActivity, 然后启动的 CommonActivity
其中 IndexActivity 的 LaunchMode 设置 singleTask, 此时 MainActivity 和 CommonActivity 和 App1 的 TestActivity 在同一个任务栈, IndexActivity 因为 singleTask 是会新开一个任务栈,(如果 IndexActivity 没有指定 taskAffinity, 那么这个任务栈名字就是 App2 包名, 如果指定了 taskAffinity 就会用 taskAffinity 指定的名字), 本来 CommonActivity 是在 IndexActivity 之后启动的, 但是因为 IndexActivity 所在任务栈是新创建的, 这样就会使 IndexActivity 在前台而显示出来, 显示在最上面, 此时按返回键会先 finish IndexActivity 然后显示出来 CommonActivity
以普通模式启动的 activity 会进入启动它的 activity 的任务栈, 当 MainActivity 启动了 IndexActivity 和 CommonActivity, 因为 MainActivity 是普通模式启动的, 会被加到 App1 的 TestActivity 所在的任务栈, CommonActivity 也是普通模式启动, 会被加到 MainActivity 所在任务栈也就是 TestActivity 的任务栈, 设置他们的 taskAffinity 也没用 (只有 singleTask,singleInstance 这样会创建新任务栈的才有用), 这样 MainActivity 和 CommonActivity 都在 TestActivity 所在的任务栈中, 要想达到前台显示的是 CommonActivity, 就必须让 MainActivityIndexActivityCommonActivity 在一个任务栈, 所以可以把 MainActivity 的启动模式也设置为 singleTask, 这样 MainActivity 被加到了一个新任务栈 (如果不指定 taskAffinity, 那么这个任务栈名字就是 App2 包名),MainActivity 再启动了 IndexActivity 和 CommonActivity, 并且 IndexActivity 不指定 taskAffinity(默认使用包名作为任务栈名), 这样和 MainActivity 任务栈名字一样, 加到 MainActivity 所在任务栈, CommonActivity 是普通模式启动, 也会加入到启动者 MainActivity 所在任务栈, 这样三者就都在一个任务栈中了, 因为 CommonActivity 是后启动的, 它会显示在前台, 所以问题就是这样
附加
还有 singleInstance 启动的, 同样指定了 taskAffinity 就用指定的作为任务栈名, 没有指定就用包名, 会创建一个新任务栈 A(如果有同名的任务栈表示已经创建过了就重用, 不会创建新任务栈) 并且里面只有一个 Activity, 哪怕后面他又启动了一个 singleTask 的 Activity 并且任务栈名字相同也不会影响任务栈 A,singleInstance 启动的 Activity 所在的任务栈如果没有就创建, 如果有就重用, 并且里面只有一个 Activity
思考
前面提到的 taskAffinity, 回到最开始的问题, 假如我把 MainActivity 的 taskAffinity 指定为 App2 包名, 这样虽然 App2 的 IndexActivity 的启动模式是 singleTask, 但是他们任务栈名字一样应该会在同一个任务栈吧其实是不行的, taskAffinity 可以和 allowTaskReparenting 配合使用, 当 allowTaskReparenting 设为 true 时, 同时指定 taskAffinity 等于 App2 的包名, 还是像开始的那样操作, MainActivity 和 CommonActivity 还是会在 App1 的 TestActivity 的任务栈中, 当按了 Home 键回到桌面后在打开 App2, 此时 MainActivity 才会在以 App2 包名命名的任务栈中
来源: https://juejin.im/post/5ab26b4c5188255580022144