Android Fragments: Fragment Result

Passing data between Fragment
s can be achieved in various ways, including using the target Fragment
APIs (Fragment.setTargetFragment()
and Fragment.getTargetFragment()
), ViewModel
or the Fragment
s’ parent Activity
. The target Fragment
APIs have recently been deprecated, and the encouraged way to pass data between Fragment
s is now the Fragment
result APIs, where passing the data is handled by a FragmentManager
, and Fragment
s can be set up to receive and send data.
Passing Data Between Fragments
To pass data between 2 Fragment
s without them having references to each other, you can now use their common FragmentManager
, which acts as a central store for data passed between Fragment
s.
Receiving Data
If a Fragment
expects to receive data, it can register a FragmentResultListener
on a FragmentManager
and specify a key to identify the data it expects, this acts as a filter to the data the FragmentManager
sends it.
The lifecycleOwner
argument allows for data to be received only if it’s at least in a STARTED
state. If the LifecycleOwner
is the Fragment
itself, you can safely update the UI when new data is received, since the View
will have been created by that point (onViewCreated()
is called before onStart()
).

If multiple data is passed to the Fragment
before it reaches the STARTED
state, it’ll only receive the latest value if it eventually reaches the STARTED
state.

When the LifecycleOwner
reaches the DESTROYED
state, it automatically unregisters the listener. To manually unregister it beforehand, call FragmentManager.setFragmentResultListener()
again with the same request key, only this time pass in a null
FragmentResultListener
.

The FragmentManager
used to register the listener depends on the Fragment
s that can send back data.
- If
FragmentA
expects to receive data fromFragmentB
and both are on the same level, they can both communicate through their parentFragmentManager
, andFragmentA
must register its listener using its parentFragmentManager
.
- If
FragmentA
expects to receive data fromFragmentB
andFragmentA
isFragmentB
’s parent, they can both communicate throughFragmentA
’s childFragmentManager
, which isFragmentB
’s parentFragmentManager
.
Essentially, the listener must be set on a common FragmentManager
.
Sending Data
If FragmentB
needs to send data to FragmentA
, it can pass it through a common FragmentManager
(the parent FragmentManager
) using the request key FragmentA
registered its listener with.
Testing Fragment Results
To test that a Fragment
receives or sends data successfully, you can use the FragmentScenario
API, which provides the benefit of testing your Fragment
in isolation.
Receiving Data
If FragmentA
registers a FragmentResultListener
to receive data, you can simulate the action of sending this data using the Fragment
’s parent FragmentManager
. If FragmentA
’s listener is set up correctly, it should receive the data, verify this by either retrieving it from FragmentA
, or verifying a side effect of the reception, for example, if FragmentA
displays data it receives on the UI, verify the expected data is displayed using Espresso
APIs.
Sending Data
You can test whether FragmentB
correctly sends data by setting up a FragmentResultListener
on its parent FragmentManager
inside the test, sending the result, then verifying the listener successfully received the data.
Sample Project
Below is a sample project that demonstrates using the Fragment
Result APIs.
Conclusion
While the deprecation of the Fragment
target APIs and their replacement with the Fragment
result APIs is a bit limiting since the latter only allows for Bundle
s to be passed, thus only simple type, Serializable
and Parcelable
data can be passed, the Fragment
result APIs allow to properly recover from process death and to pass data between Fragment
s without the need to hold references to each other, which prevents issues that may occur from accessing a Fragment
in an unpredictable state.
Want more Fragment
s goodness? Check out: