Sebastian Labadie
Sebastian Labadie

Reputation: 161

setFragmentResult doesn't work onClick listener

hello my problem is the following, I have 2 fragments, one receives with SetFragmentResultListener and another sends with setFragmentResult

The problem is that setFragmentResult does not work inside an OnClickListener but it does work outside

Parent

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

Child - It Work

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
    }

Child - It doesn't Work

 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
    }

Upvotes: 16

Views: 19976

Answers (5)

xinyu li
xinyu li

Reputation: 1039

Call setFragmentResultListener in onViewCreated method of your parent fragment.

Because according to the source code of FragmentManager, the FragmentResultListener would be removed when parent fragment's onDestroyView called, so when you go back to parent fragment, you should register the listener again in order to make sure it is called after parent fragment start.

Upvotes: 0

bluestart83
bluestart83

Reputation: 337

In my case sending result from pushed fragment to presenting, I need to call: requireActivity().onBackPressed(), then setFragmentResult().

Upvotes: 0

fif.iva
fif.iva

Reputation: 181

In the case of passing data from Child to Parent fragment, using the childFragmentManager is the key when setting the resultListener on the parent fragment.

  • Parent fragment (place the code inside onCreate()):
childFragmentManager.setFragmentResultListener("requestKey", this ) { requestKey, bundle ->
            val resultReceived = bundle.getString("bundleKey")
            // do something with the result
            // ...  
        }
  • Child fragment (place the code whenever you need to send the result - could be from a click listener, could be once you receive a result from another started activity for result, etc.):
 val resultToBeSent = "result"
 setFragmentResult("requestKey", bundleOf("bundleKey" to resultToBeSent))

More useful information about the communication between fragments can be found in this medium article: The modern way to pass data between fragments and of course in the official Android documentation: Communicating with fragments.

Upvotes: 13

Franbede
Franbede

Reputation: 648

As per @ianhanniballake's answer, I went a bit further, because I had a similar problem, and read the documentation he referred (specially, the Receive results in the host activity section). One of the keys in making inter-fragment communication (parent-child) is to use activity's supportFragmentManager methods to perform the information exchange. Example:

  • Parent fragment (host)
requireActivity().supportFragmentManager
   .setFragmentResultListener("whatever_id_you_use", viewLifecycleOwner) {
   // Your code for listener
}
  • Child fragment:
requireActivity().supportFragmentManager
   .setFragmentResult("whatever_id_you_use", bundle_with_results)

"whatever_id_you_use" is the requestKey depicted in documentation, which is the index the activity will look for when assigning a listener to its result. Doing this way should keep the listeners in sync with the lifecycle, while simplifying own listener's implementation.

Upvotes: 25

ianhanniballake
ianhanniballake

Reputation: 200080

When you use the Navigation Component, the previous fragment is stopped when you navigate to a new fragment. As per the Fragment Result API guide:

If you call setFragmentResult() more than once for the same key, and if the listener is not STARTED, the system replaces any pending results with your updated result. If you set a result without a corresponding listener to receive it, the result is stored in the FragmentManager until you set a listener with the same key. Once a listener receives a result and fires the onFragmentResult() callback, the result is cleared. This behavior has two major implications:

  1. Fragments on the back stack do not receive results until they have been popped and are STARTED.
  2. If a fragment listening for a result is STARTED when the result is set, the listener's callback is then fired immediately.

So it is expected that you do not get any calls to your fragment result listener until you pop back to that fragment and it becomes STARTED again.

Upvotes: 6

Related Questions