Search code examples
androidandroid-fragmentsandroid-architecture-componentsandroid-viewmodelandroid-safe-args

Which is the better way to share data between Fragments?


I want to share a few Integer values from one fragment to the other. I don't want lose the data when the device changes configuration.

So the two ways that I came across and want to know which one will be better for my use case are:

1. Sharing a ViewModel among multiple fragments

class SharedViewModel : ViewModel(){
    ...
}

class FragmentA : Fragment(){
    private val model: SharedViewModel by activityViewModels()
    ...
}

class FragmentB : Fragment(){
    private val model: SharedViewModel by activityViewModels()
    ...
}

2. Using combination of SafeArgs and custom ViewModelProvider.Factory

Using SafeArgs to pass data as a parameter to a navigation action from a fragment (say A) to another fragmet (say B). Implementing ViewModel (parameterized) and ViewModelFactory classes for fragment B. Passing the data from SafeArgs to ViewModelFactory to create a ViewModel (using ViewModelProvider)

Something like this:

class B : Fragment() {

    //Seperate classes for ViewModelB & ViewModelFactoryB
    private lateinit var viewModel: ViewModelB
    private lateinit var viewModelFactory: ViewModelFactoryB

    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View? {

        val binding: BFragmentBinding = DataBindingUtil.inflate(
                inflater,
                R.layout.b_fragment,
                container,
                false
        )

        viewModelFactory = ViewModelFactoryB(BFragmentArgs.fromBundle(requireArguments()).data)
        viewModel = ViewModelProvider(this, viewModelFactoryB).get(ViewModelB::class.java)

        return binding.root
    }
}

Solution

  • It totally depends on your use case, what data you share between fragments and how it is used.

    Even though both cases support passing custom objects you have to consider a few things.

    In the case of the navigation component, regarding custom objects:

    • data must be either Parcelable (preferred) or Serializable;
    • all of the data passed through using Bundle object which has its own limitations and with large data can lead to TransactionTooLargeException (more about it). It can be easily avoided when using shared view model.

    In the case of shared view models:

    • you have to define new classes to wrap your models;
    • you have to add new class members to hold shared view models;
    • a shared view model will take memory until Activity is finished or the view model store is cleared.

    So what is the answer?

    Such a question leads to opinionated answers, but I consider following a set of hints to use when choosing between safe argument and shared view model.

    Use safe arguments when:

    1. data is small;
    2. when you do not need to return results to the previous fragment after using this data;
    3. you do not care if this data is removed from memory when you are done with it and you have to query it again each time.

    Use a shared view model when:

    1. data is relatively large or you assume it could be large;
    2. you have multiple data models/sets;
    3. when you do need to return results to the previous fragment after using this data;
    4. when data is expensive to query. Shared view models typically live as long as the activity.