NavController导航时setFragmentResultListener不生效问题
你的setFragmentResultListener无法触发,本质是违反了Fragment Result API的两个核心规则:
- 发送结果、注册监听器必须绑定同一个FragmentManager实例
- 注册监听器的Fragment必须处于
STARTED及以上生命周期状态,才会接收到结果。如果监听器所属Fragment在结果投递前就被销毁,结果会直接丢弃。
你的导航链路是ListFragment → DetailFragment → OperationFragment:当你在OperationFragment中调用接口时,DetailFragment已经被压入返回栈,生命周期停在STOPPED状态;如果你发完结果直接执行退栈操作回到ListFragment,DetailFragment会被直接销毁,永远不会进入STARTED状态,监听器自然不可能触发。
额外的写法问题:NavController管理的Fragment各自持有导航栈对应的FragmentManager,直接拿父级Activity的parentFragmentManager收发结果,很容易出现收发双方实例不匹配的问题。
你不需要绕经DetailFragment做中转,直接在OperationFragment和ListFragment之间通信,操作完成后直接返回ListFragment即可,步骤如下:
- 在ListFragment的
onCreate阶段注册结果监听器:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setFragmentResultListener("operation_finish_key") { _, bundle -> val result = bundle.getString("bundleKey") // 在这里直接处理返回结果,比如刷新列表数据 } }
- 在OperationFragment接口请求成功后,先向ListFragment对应的导航栈入口发送结果,再直接导航回ListFragment:
// 接口响应成功后执行 val resultToBeSent = "result" // 获取ListFragment对应的返回栈实例,替换R.id.list_fragment为你导航图中ListFragment定义的id val listEntry = findNavController().getBackStackEntry(R.id.list_fragment) // 向ListFragment发送结果 listEntry.fragmentManager?.setFragmentResult( "operation_finish_key", bundleOf("bundleKey" to resultToBeSent) ) // 直接弹出栈上的DetailFragment、OperationFragment,回到ListFragment findNavController().popBackStack(R.id.list_fragment, false)
这种写法不会破坏你ListFragment原有存在Bundle里的数据,也不需要无意义的页面中转,稳定性最高。
避坑提醒:不要给处于后台状态的Fragment发结果后立刻销毁它,这种场景下监听器永远不会执行。如果只需要跨层给返回栈里的Fragment发结果,直接通过NavController拿到目标Fragment对应的栈入口操作即可,不要随便用全局的parentFragmentManager。
内容的提问来源于stack exchange,提问作者Rahul Matte

