Android registerForActivityResult回调内启动Activity时回调未触发问题
这是Android Activity Result API的机制限制:ActivityResultRegistry分发返回结果时会持有同步分发状态标记,整个分发流程是同步执行的。如果在某一个launcher的回调中同步触发另一个launcher的launch()调用,此时前一次结果分发还未结束,新launcher的请求码和回调的映射关系不会被正确注册到分发链路中。
后续第二个Activity销毁返回时,宿主Activity虽然能在onActivityResult层面收到原始结果,但ActivityResultRegistry无法将结果匹配到对应的launcher回调,就会出现你观察到的现象:宿主层能收到回调,但通过registerForActivityResult注册的业务回调不触发。
方案1:主线程延迟启动(兼容性最好,推荐优先使用)
将回调内的启动逻辑延迟到主线程下一个消息循环执行,等前序结果分发完全结束、状态标记重置后再启动第二个Activity,不需要升级依赖,兼容所有API版本:
val activityALauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { res -> if (res.resultCode == Activity.RESULT_OK) { // 依赖Fragment的View做post,页面销毁时会自动移除回调,避免内存泄漏 view?.post { launchActivityB() } // 无可用View时可以直接用主线程Handler // Handler(Looper.getMainLooper()).post { launchActivityB() } } }
这个方案不会破坏现有API的生命周期逻辑,配置变更、Fragment重建场景下都能正常工作,是生产环境验证过的稳定方案。
方案2:升级AndroidX Activity依赖
在androidx.activity:activity-ktx:1.8.0及以上版本中,官方修复了同步嵌套启动Activity Result Launcher的回调丢失问题。升级后不需要额外加延迟,直接在回调中调用launch()也可以正常收到结果。
升级时需要注意同步匹配AppCompat、Fragment等关联依赖的版本,避免依赖冲突。
- 不要通过重写宿主Activity的
onActivityResult手动分发结果,这种方式会破坏Activity Result API自带的生命周期绑定能力,在配置变更、Fragment重建场景下容易出现内存泄漏、回调错位问题。 - 如果存在连续启动多个Activity的场景,可以维护一个轻量的待启动任务队列,每次launcher回调执行完成后,通过post的方式依次取出队列任务执行,避免多层嵌套调用引发状态异常。
内容的提问来源于stack exchange,提问作者User88909000

