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

stamanuel picture stamanuel · Nov 23, 2017 · Viewed 9.2k times · Source

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?

Answer

karthik prasad picture karthik prasad · Mar 14, 2018

I think the concept behind the ViewModel was that it is supposed to be related to a single "Screen" rather than a "View". So going by that logic, I think you can use the same ViewModel if multiple fragments reference the same ViewModel because they technically belong to the same "Screen".

In the fragments, you could request the activity for the ViewModel which holds the instance of LiveData and could give you the updates as needed.

Hope this answers your question.

Update: I found a link to a sample fragment in Google samples. Check out onCreateView() method. Pasting code below for reference:

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    final View root = inflater.inflate(R.layout.addtask_frag, container, false);
    if (mViewDataBinding == null) {
        mViewDataBinding = AddtaskFragBinding.bind(root);
    }

    mViewModel = AddEditTaskActivity.obtainViewModel(getActivity());

    mViewDataBinding.setViewmodel(mViewModel);

    setHasOptionsMenu(true);
    setRetainInstance(false);

    return mViewDataBinding.getRoot();
}

P.S. If you have found a better solution/answer/practice, lemme know.