How to Share Data Between Fragments?
In day-to-day feature development, we often encounter the need to share data between Fragments – for example, passing data from Fragment A to Fragment B. What approaches can achieve this?
The Naive Approach
The first thing that comes to mind is adding a field to the Activity:
MainActivity.kt
1 | class MainActivity : FragmentActivity() { |
This way, Fragments can access the shared data through MainActivity:
Fragment1.kt
In Fragment1, fetch data from the API, then update it in MainActivity:
1 | class Fragment1 : Fragment() { |
Fragment2.kt
When Fragment2 is created, retrieve the shared data from MainActivity and update the UI:
1 | class Fragment2 : Fragment() { |
This does solve the data sharing problem, but can you spot the drawbacks?
SharedDatais actually maintained byFragment1. Putting it inMainActivitymakes the ownership ofSharedDataunclear.If other data needs to be shared between different
Fragments, piling everything intoMainActivityadds unnecessary burden and is outsideMainActivity‘s responsibility.If
Fragment1is used not only inMainActivitybut also in otherActivitys, how do you ensureFragment1can be reused across differentActivitys without extra maintenance cost?
The Elegant Approach
The drawbacks of the previous approach boil down to two issues:
- Responsibility
- Scalability
The ideal solution should satisfy:
SharedDatashould only be maintained byFragment1MainActivityshould not need any modifications
If we meet these conditions, Fragment1 would look like this:
1 | class Fragment1 : Fragment() { |
But this raises a few questions:
- How can
Fragment2conveniently get a reference toSharedDatafromFragment1? - If
Fragment1is destroyed,SharedDatagoes with it. How do we bindSharedData‘s lifecycle toMainActivity?
To address these questions, we can use the following approach:
LifecycleScope.kt
1 | object LifecycleScope : LifecycleObserver { |
Fragment1.kt
1 | class Fragment1 : Fragment() { |
Fragment2.kt
1 | class Fragment2 : Fragment() { |
This way, MainActivity doesn’t need any modifications, the Activity doesn’t care about sharing behavior between Fragments, Fragments become more cohesive, and they can be reused in other Activitys at zero cost.
The Perfect Approach
The elegant approach works, but it requires an extra LifecycleScope class, and LifecycleScope is a singleton. While it won’t cause performance issues, it still feels less than perfect. Is there a better solution?
In fact, Android already provides one out of the box – ViewModel. Here’s what the implementation looks like using ViewModel:
SharedViewModel.kt
1 | class SharedViewModel : ViewModel() { |
Fragment1.kt
1 | class Fragment1 : Fragment() { |
Fragment2.kt
1 | class Fragment2 : Fragment() { |
Normally, when using ViewModel in a Fragment, you call the viewModels() extension function and create a ViewModel delegate via by. This delegate is bound to the Fragment‘s lifecycle. To keep the shared data available even after a Fragment is destroyed, you use activityViewModels() instead, which binds the ViewModel delegate to the Activity‘s lifecycle.
- Blog Link: https://johnsonlee.io/2020/12/05/sharing-data-between-fragments.en/
- Copyright Declaration: 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
