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

12,709

Solution 1

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);

Solution 2

Using Fragment-ktx we can do as In **ParentFragment**

 private val viewModel: DemoViewModel by viewModels()

And

In ChildFragment

 private val viewModel: DemoViewModel by viewModels(
    ownerProducer = { requireParentFragment() }
)

Doing this we can get same instance of ViewModel in Parent Fragment and ChildFragment

add dependencies in app -> build.gralde

implementation 'androidx.fragment:fragment-ktx:1.1.0

Solution 3

Implement fragment-ktx in your app -> build.gradle:

implementation 'androidx.fragment:fragment-ktx:1.2.5

If you are using Navigation Component (https://developer.android.com/guide/navigation)

In the parentFragment, you can get the viewModel like this:

private val viewModel by viewModels<DemoViewModel>()

And then when you need that viewModel in the childFragment you can get it this way:

private val viewModel by viewModels<DemoViewModel>({requireGrandParentFragment()})

the requireGrandParentFragment() is a custom extension of Fragment:

fun Fragment.requireGrandParentFragment() = this.requireParentFragment().requireParentFragment()

If you are not using Navigation Component

you can access it like this:

private val viewModel by viewModels<DemoViewModel>({requireParentFragment()})

Solution 4

I have got a same problem tried above all solution but not working in my scenario come up with a other solution using requireParentFragment() return NavHostFragment in child fragment solve it by using

private val viewModel: childViewModel by viewModels(
            ownerProducer = { requireParentFragment().childFragmentManager.primaryNavigationFragment!! }
    )

in Parent Fragmet use this

private val viewModel: MyOrdersVM by viewModels()
Share:
12,709

Related videos on Youtube

mhtmalpani
Author by

mhtmalpani

Updated on March 31, 2022

Comments

  • mhtmalpani
    mhtmalpani about 2 years

    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.

  • mhtmalpani
    mhtmalpani about 6 years
    Thank you. This works smooth! Just for the knowledge, the Parent and Child fragment scopes are alive at the same time. How can achieve the same thing without using the Activity?
  • Fazal Hussain
    Fazal Hussain almost 6 years
    How to share movieListViewModel to different module? Is that possible
  • A. Kazarovets
    A. Kazarovets over 5 years
    What about single activity approach? It won't be good to hold all the shared view models linked to one activity.
  • Zain
    Zain over 5 years
    just a modification to avoid NullPointerException movieListViewModel = ViewModelProviders.of(requireActivity()).get(MovieListViewMo‌​del.class);
  • Victor Okech
    Victor Okech over 3 years
    To add on this is it possible to get the view model for a separate activity to send data to the child fragment of the MainActivity?