Shared ViewModel in scope of parent fragment using Navigation Component
J

2

10

I am trying to use the same instance of ViewModel in Parent Fragment and its children, using Navigation Component. The hierarchy is as follows: Single Activity that has navigationHost. This host has 3 child fragments, A, B and C. The last fragment has also navigationHost with 2 fragments: X and Y. The below graph illustrates the hierarchy.

Fragments hierarchy

Expected: I would like to share the same instance of fragment C ViewModel with fragment X and Y.

Current: The ViewModel of fragment C is initialized twice: Once when fragment C is initialized and second time when fragment X is initialized. The Fragment X is set as a default destination in the fragment C nav graph. When I am changing the default destination to Y, the ViewModel is initialized in C and Y.

What I tried already: In child viewModels I use this:

        val viewModel: ParentViewModel =
        ViewModelProvider(findNavController().getViewModelStoreOwner(R.id.parent_graph)).get(
            ParentViewModel::class.java
        )

In parent viewModel I use this:

    val viewModel by viewModels<ParentViewModel>()

I've also tried to inject the viewModel using Koin sharedViewModel with scope of fragment:

val viewModel by sharedViewModel<ParentViewModel>(from = { parentFragment!! })

Also no luck.

Is it possible or maybe it is a bug in navigation library?

Jesse answered 22/2, 2020 at 20:30 Comment(0)
A
18

A NavHostFragment is a fragment itself, so your structure is actually

Fragment C -> NavHostFragment -> Fragment X
                              -> Fragment Y

I.e., the parentFragment you get from Fragment X is not Fragment C - it is the NavHostFragment you added in between the two.

Therefore if you want to get a ViewModel from Fragment C, you'd need to use requireParentFragment().requireParentFragment() - the parent of your NavHostFragment is Fragment C.

Afreet answered 22/2, 2020 at 21:18 Comment(1)
That works, thanks 🙏 . I used the koin sharedViewModel(from = { requireParentFragment().requireParentFragment() }) Can that result be achived when using getViewModelStoreOwner ? As I understand creating the ViewModel in the scope of the nested navigation graph will give me the scope of the navHost, which is different fragment than FragmentC.Jesse
U
1

Cannot find a parameter with this name: from ------------update----------------

for those facing the same issue, check here koin issue discuss about, and maybe here might be helpful.

I'm using

//child fragment    
    private val viewModel: TripParentViewModel by viewModel(owner = { ViewModelOwner.Companion.from(requireParentFragment().requireParentFragment().viewModelStore)})

//parent fragment
private val parentViewModel by viewModel<TripParentViewModel>()

as solution,

class TripParentViewModel:ViewModel() {

    var count = 0
    fun test(){
        when(count){
            0 -> Timber.d("first click")
            1 -> Timber.d("second click")
            2 -> Timber.d("third click")
        }
        Timber.d(count.toString())
        count++
    }
}

currently, I run this when change fragment, I didn't see any problem so far, if anything goes wrong, I will update here

  • koin_version = "2.2.1"
  • navigation_version = "2.3.5"
Uncouth answered 2/8, 2021 at 9:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.