How to give same instance of ViewModel to both the Parent and Child fragment

mhtmalpani picture mhtmalpani · May 26, 2018 · Viewed 10.4k times · Source

There are two Fragments: ParentFragment and ChildFragment. ChildFragment has been added to a view of the ParentFragment.

Now using Dagger2 for Android has the ParentFragmentModule with a method:

@Provides
fun provideViewModel(fragment: ParentFragment, myViewModelFactory: MyViewModelFactory): MyViewModel {
    return ViewModelProviders.of(fragment, myViewModelFactory).get(MyViewModelImpl::class.java)
}

Where MyViewModelFactory, MyViewModel, MyViewModelImpl are simple ViewModel logic created in the app.

And the ChildFragmentModule has the method:

@Provides
fun provideViewModel(fragment: ChildFragment, myViewModelFactory: MyViewModelFactory): MyViewModel {
    return ViewModelProviders.of(fragment, myViewModelFactory).get(MyViewModelImpl::class.java)
}

This obviously is creating two separate instances of the ViewModel as they receive two different fragment instances.

How do we make it return the same instance so that the data can be shared between both the Parent and Child fragments?

I have tried passing the ParentFragment instead of ChildFragment in the ChildFragmentModule, but that leads to Dagger dependancy injection error.

Answer

Abu Yousuf picture Abu Yousuf · May 26, 2018

Create your ViewModel with Activity scope. Then all Fragment within that Activity will get same ViewModel instance.

Check official ViewModelProviders reference. You can create ViewModel with both Activity and Fragment scope.

ViewModelProvider of (FragmentActivity activity)

Creates a ViewModelProvider, which retains ViewModels while a scope of given Activity is alive. More detailed explanation is in ViewModel.

and

ViewModelProvider of (Fragment fragment)

Creates a ViewModelProvider, which retains ViewModels while a scope of given fragment is alive. More detailed explanation is in ViewModel.

Sample code for creating ViewModel

From Activity:

 movieListViewModel = ViewModelProviders.of(this).get(MovieListViewModel.class);

From Fragment:

 movieListViewModel = ViewModelProviders.of(getActivity()).get(MovieListViewModel.class);