前言
最近项目中遇到了一个奇怪的问题,大概是这样子的:某个页面调起扫码页面,成功后返回对应数据,然而据用户反馈,有些手机扫码成功后无法继续操作。当时测试机上也没有这种情况发生,所以暂时搁置了。直到公司来了一台Android4.4的设备...
测试了一下,果然复现了!不得不说测试机还是有必要覆盖所有Android版本的!调试中很快就发现了问题,从Logcat中隐约感觉是onActivityResult()方法提前执行了,目标Activity还没finish就直接回调,结果拿不到任何数据,导致了这个问题。值得一提的是,这个问题在Android5.0以上版本却没有任何问题。
验证
一番调试与查看API过后,定位了这个问题发生的原因:由于目标Activity设置了一个launchMode = "singleTask"
For example, if the activity you are launching uses the singleTask launch mode, it will not run in your task and thus you will immediately receive a cancel result.
测试1:将目标Activity启动模式设置为singleTask,在Android4.4系统中运行结果:

测试2:将目标Activity启动模式设置为singleTop,在Android4.4系统中运行结果:

结论
实测,将目标Activity的launchMode改为standard、singleTop则代码可在Android4.4上正常运行,感兴趣的可以亲自试试,可以分别控制变量设置启动Activity、目标Activity的启动模式,测试其在各种条件下的运行状态。
通过踩坑发现,Android的版本问题不容小视,而老生常谈(特别是面试的)的启动模式缺乏实战的指导,不免泛泛而谈,只有真正的实战中才能发现一些问题。在低版本Android(4.x)系统上startActivityForResult()方法在某些launchMode下的数据传递存在问题,幸好谷歌意识到了这个问题并在5.0以上的版本修复。但是考虑到兼容问题还是要谨慎使用LaunchMode,切勿理所当然的指定启动模式。
Android launchMode 相关回顾
Activity 的launchMode共有四种模式

- standard,默认启动模式,每次新建实例。
- singleTop,若栈顶不是该类型的Activity,新建实例。否则,onNewIntent。
- singleTask,若回退栈中没有该类型的Activity,新建实例,否则,onNewIntent+ClearTop。
- singleInstance,共享的独立任务栈,栈中只有这一个Activity,没有其他Activity。
“standard”和“singleTop”模式只在一个方面有差异:
每次“standard”Activity 有新的 Intent 时,系统都会创建新的类实例来响应该 Intent。每个实例处理单个 Intent。同理,也可创建新的“singleTop”Activity 实例来处理新的 Intent。
不过,如果目标任务在其堆栈顶部已有一个 Activity 实例,那么该实例将接收新 Intent(通过调用 onNewIntent();此时不会创建新实例。在其他情况下例如,如果“singleTop”的一个现有实例虽在目标任务内,但未处于堆栈顶部,或者虽然位于堆栈顶部,但不在目标任务中则系统会创建一个新实例并将其推送到堆栈上。同理,如果您向上导航到当前堆栈上的某个 Activity,该行为由父 Activity 的启动模式决定。 如果父 Activity 有启动模式 singleTop则系统会将该父项置于堆栈顶部,并保留其状态。 导航 Intent 由父 Activity的 onNewIntent()方法接收。 如果父 Activity 有启动模式 standard,则系统会将当前 Activity 及其父项同时弹出堆栈,并创建一个新的父 Activity 实例来接收导航 Intent。
“singleTask”和“singleInstance”模式同样只在一个方面有差异:
“singleTask”Activity 允许其他 Activity 成为其任务的组成部分。它始终位于其任务的根位置,但其他Activity(必然是“standard”和“singleTop”Activity)可以启动到该任务中。 相反,“singleInstance”Activity 则不允许其他 Activity 成为其任务的组成部分。它是任务中唯一的 Activity。 如果它启动另一个 Activity,系统会将该 Activity 分配给其他任务一样。
参考资料
启动模式及其与 Intent 标志交互文档
解决 singleTask onActivityResult() 无效的问题
网友评论