Android MVVM: Activity with multiple Fragments - Where to put shared LiveData?

Viewed 11427

I have an architectural question about the android ViewModels:

Let's say that in my App I have an Activity with two Fragments inside (using a Viewpager). The two fragments do different things (therefore may have their own ViewModel?), but they also both need various data that is similar.

This is for example the state if a network connection is available or not (and both fragments show different error UIs if there is no connection), or some user setting that comes via a Push from a server and affects both fragments equally.

This looks something like this:

enter image description here

Now my question is how to deal with that situation when using ViewModels? Is it good that a view observes multiple ViewModels, like it would be if I have a ViewModel for the Activity (holding the state that both need equally) and one for each fragment, like this:

enter image description here

This was hinted here for example, but it is not a good practice, as the relationship in MVVM generally is

View n - 1 ViewModel n - 1 Model

But I am not sure where the right place for such shared LiveData is in my case?

2 Answers

Late answer but I asked myself the same question and found the answer in Google guide. Especially for fragments, it is mentioned on Google Documentations explicitly here

class SharedViewModel : ViewModel() {
    val selected = MutableLiveData<Item>()

    fun select(item: Item) {
        selected.value = item
    }
}

class MasterFragment : Fragment() {

    private lateinit var itemSelector: Selector

    // Use the 'by activityViewModels()' Kotlin property delegate
    // from the fragment-ktx artifact
    private val model: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        itemSelector.setOnClickListener { item ->
            // Update the UI
        }
    }
}

class DetailFragment : Fragment() {

    // Use the 'by activityViewModels()' Kotlin property delegate
    // from the fragment-ktx artifact
    private val model: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        model.selected.observe(viewLifecycleOwner, Observer<Item> { item ->
            // Update the UI
        })
    }
}
Related