setFragmentResult在onClick监听器中不起作用。

14

你好,我的问题如下:我有两个Fragment,一个使用SetFragmentResultListener接收信息,另一个使用setFragmentResult发送信息。

问题是setFragmentResult在OnClickListener内部不起作用,但在外部可以正常工作。

父级Fragment

 setFragmentResultListener("scannedCode") { requestKey, bundle ->
                val result = bundle.getString("code")
                Log.i("MYLOG-find","$result")
            }

儿童——它的工作

override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_scan, container, false)

            setFragmentResult("scannedCode", bundleOf("code" to  "pedro"))
        
        return view
    }

孩子 - 它不起作用了

 override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_scan, container, false)

        view.textView2.setOnClickListener {
            setFragmentResult("scannedCode", bundleOf("code" to  "pedro"))
        }

        return view
    }

1
setFragmentResultListener 函数到底在哪里被调用了? - EpicPandaForce
这是父片段 https://ibb.co/GRJzKvL 而这是子片段 https://ibb.co/sRPKDbK - Sebastian Labadie
主要片段已设置setFragmentResultListener,次要片段中红线不起作用,蓝线正常工作。 - Sebastian Labadie
2
看起来你正在使用导航组件(这些实际上不是父/子片段,即使用childFragmentManager)。你为什么不使用导航API返回结果呢? - ianhanniballake
要准确说,只有在我执行popBackStack()时红色线才起作用。 - Sebastian Labadie
显示剩余2条评论
4个回答

19

根据 @ianhanniballake 的回答,我进一步探索了一下,因为我遇到了类似的问题,并阅读了他所提到的文档(特别是在宿主 Activity 中接收结果部分)。在实现片段间通信(父子)时,使用 Activity 的 supportFragmentManager 方法进行信息交换是关键之一。例如:

  • 父片段(宿主)
requireActivity().supportFragmentManager
   .setFragmentResultListener("whatever_id_you_use", viewLifecycleOwner) {
   // Your code for listener
}
  • 子片段:
requireActivity().supportFragmentManager
   .setFragmentResult("whatever_id_you_use", bundle_with_results)

"whatever_id_you_use"是文档中描述的requestKey,它是活动在为其结果分配侦听器时要查找的索引。以这种方式执行应该使侦听器与生命周期同步,并简化自己的侦听器实现。


现在在切换到导航组件后,对我来说可以工作了。谢谢... - Andy Cass
但是,如果我们只是使用此 setFragmentResult("whatever_id_you_use", bundle_with_results) 该怎么办? - Qamar khan

13

当从子片段传递数据到父片段时,使用childFragmentManager是在父片段上设置resultListener的关键。

  • 父片段 (将代码放在onCreate()中):
childFragmentManager.setFragmentResultListener("requestKey", this ) { requestKey, bundle ->
            val resultReceived = bundle.getString("bundleKey")
            // do something with the result
            // ...  
        }
  • 子片段将代码放在需要发送结果的任何位置 - 可能是从单击侦听器,可能是一旦接收到来自另一个启动的活动的结果等。):
 val resultToBeSent = "result"
 setFragmentResult("requestKey", bundleOf("bundleKey" to resultToBeSent))

关于片段之间通信的更多有用信息,请参考这篇中文文章:现代化的片段之间数据传递方式,当然还有官方的安卓文档:与片段通信


5
当您使用导航组件时,当您导航到新片段时,先前的片段将停止。根据片段结果API指南
如果您对相同键调用setFragmentResult()多次,并且监听器不是STARTED,则系统将使用更新后的结果替换任何未决结果。如果设置了没有相应侦听器接收的结果,则结果存储在FragmentManager中,直到您设置具有相同键的侦听器。一旦侦听器接收到结果并触发onFragmentResult()回调,则结果将被清除。此行为具有两个主要影响:
1.回退堆栈上的片段在弹出并且是STARTED之前不会收到结果。
2.如果正在侦听结果的片段在设置结果时处于STARTED状态,则立即触发侦听器的回调。
因此,预期不会在返回到该片段并再次变为STARTED之前调用片段结果侦听器。

0
在我的情况下,从推送的片段发送结果到呈现,我需要调用:requireActivity().onBackPressed(),然后setFragmentResult()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接