4.4 Sharing Data Between Fragments

To reuse fragments, build each as a completely self-contained component that defines its own layout and behavior. Once you have defined these reusable fragments, you can associate them with an activity and connect them with the application logic to realize the overall composite UI.

To properly react to user events, or to share state information, you often need to have channels of communication between an activity and its fragments or between two or more fragments. To keep fragments self-contained, you should not have fragments communicate directly with other fragments or with its host activity.

The Fragment library provides two options for communication: a shared ViewModel and the Fragment Result API. The recommended option depends on the use case. To share persistent data with any custom APIs, you should use a ViewModel. For a one-time result with data that can be placed in a Bundle, you should use the Fragment Result API. We'll introduce the Fragment Result API here!

Pass results between fragments

First, add the dependency to your build.gradle:

implementation 'androidx.fragment:fragment-ktx:1.5.0-beta01'

To pass data back to fragment A from fragment B, first set a result listener on fragment A, the fragment that receives the result. Call setFragmentResultListener() on fragment A's FragmentManager, as shown in the following example:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // Use the Kotlin extension in the fragment-ktx artifact
    setFragmentResultListener("requestKey") { requestKey, bundle ->
        // We use a String here, but any type that can be put in a Bundle is supported,
        // remember that putExtra from intents uses a Bundle underlying, so anything
        // you putExtra works here too!
        val result = bundle.getString("bundleKey")
        // Do something with the result
    }
}

In fragment B, the fragment producing the result, you must set the result on the same FragmentManager by using the same requestKey. You can do so by using the setFragmentResult() API:

button.setOnClickListener {
    val result = "result"
    // Can also opt for an empty bundle e.g. bundleOf() with no arguments
    setFragmentResult("requestKey", 
        bundleOf("bundleKey" to result, "otherKeys" to otherResults, ...))
}

Fragment A then receives the result and executes the listener callback!

You can have only a single listener and result for a given key. If you call setFragmentResult() more than once for the same key 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.

Receiving results in Host Activity

To receive a fragment result in the host activity, set a result listener on the fragment manager using getSupportFragmentManager(). Very similar to the logic we added to our Fragment A.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        supportFragmentManager
                .setFragmentResultListener("requestKey", this) { requestKey, bundle ->
            val result = bundle.getString("bundleKey")
            // Do something with the result
        }
    }
}

Alternatives

Another option as stated previously are ViewModels (which require a little more overhead to setup) you can also opt for using Singletons, which are covered in 9.1.

Last updated