question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Hilt - injecting ViewModel via navGraphViewModels issue

See original GitHub issue

Hello, I had an issue with restoring state of injected viewmodel via navGraphViewModels. I saw the recommended way for injectig viewmodels with the Jetpack navigation library (https://github.com/google/dagger/issues/1935), 2, however after process death ViewModel is not restored correctly on the second screen of navGraph.

I created demo project which demostrates the issue. We have a nested navigation graph R.id.nested which consists of 2 fragments. Those 2 fragments shares MainViewModel and MainViewModel2 which are completely similar and contains LiveData<String>. The only difference is that first ViewModel initialized with fragment’s defaultViewModelProviderFactory as recommended with Hilt, while second is initialized without passing custom factory, so uses backStackEntry’s defaultViewModelProviderFactory (will not work when Hilt is used, but to demosntrate the problem).

    private val viewModel by navGraphViewModels<MainViewModel>(R.id.nested) {
        defaultViewModelProviderFactory
    }
    
    private val viewModel2 by navGraphViewModels<MainViewModel2>(R.id.nested)

First fragment in nested graph sets message to both viewmodels and then opens Second fragment.
With Don't keep activities enabled, putting app to background and back, triggers app process death and restore.
After process restore, MainViewModel doesn’t have the value from First fragment and shows the default one, while MainViewModel2 is restored correctly and displays proper message.

  1. Enter message on FirstFragment and open SecondFragment.
    On SecondFragment both viewmodels have correct values.
  2. Background app with Don't keep activities to trigger process death and come back.
    On SecondFragment first viewmodel doesn’t have restored value, second viewmodel has as expected.
  3. Press back to return on FirstFragment and open SecondFragment again
    On SecondFragment both viewmodels have correct values.
  4. Background app with Don't keep activities to trigger process death and come back.
    On SecondFragment both viewmodels contains correct value, even if you modify value on FirstFragment.
  5. Press back to return on FirstFragment, Background app with Don't keep activities and open SecondFragment. On SecondFragment both viewmodels have correct values.
  6. Background app with Don't keep activities to trigger process death and come back.
    On SecondFragment first viewmodel doesn’t have restored value, second viewmodel has as expected.

demo

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:7
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

9reactions
danysantiagocommented, Nov 5, 2020

The root cause of the issue is that the defaultViewModelProviderFactory from an activity or fragment uses the activity itself as the SavedStateRegistryOwner and that is different from the ViewModelStoreOwner used by the NavBackStack. It seems these two should be the same, which is exactly what is going on with the HiltViewModelFactory too, it uses the activity or fragment as SavedStateRegistryOwner which is different from the ViewModelStoreOwner that is used by the ViewModelProvider by theNavBackStack.

We are investigating a solution but sadly I don’t have a workaround for now. We might either expose a builder / factory for HiltViewModelFactory (which is odd) or we might work with AndroidX itself to make it so that these two owners are in sync.

7reactions
Zhuindencommented, Jan 28, 2021

Fixed by hiltNavGraphViewModels in hilt-navigation-fragment

Read more comments on GitHub >

github_iconTop Results From Across the Web

Hilt - injecting viewmodel via navGraphViewModels #1935
Hello, I had an issue with the following construct inside an AndroidEntryPoint annotated fragment: private val scanViewModel: ScanViewModel ...
Read more >
Hilt Doesn't Inject a Scoped ViewModel - Stack Overflow
Use hiltNavGraphViewModels from androidx.hilt:hilt-navigation-fragment instead of navGraphViewModels.
Read more >
Use Hilt with other Jetpack libraries - Android Developers
Inject ViewModel objects with Hilt. Provide a ViewModel by annotating it with @HiltViewModel and using the @Inject annotation in the ViewModel ...
Read more >
Passing Safe Args to your ViewModel with Hilt - ProAndroidDev
UPDATED for Hilt 2.31, which supports injecting ViewModels. ... So how do we pass a Safe Args argument to a ViewModel instance obtained...
Read more >
Full Guide to Dependency Scopes with Dagger-Hilt - YouTube
Proper scoping with Hilt can be quite difficult at first. Yet, using the wrong scope in the wrong cases can lead to serious...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found