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.

Dagger/Hilt ViewModel Injection (with compose and navigation-compose)

See original GitHub issue

Hello,

I am currently trying to build an app with only Compose (meaning no Fragments and navigation-compose, along with architecture components such as Hilt and ViewModel).

I tried using the viewModel function with the defaultViewModelProviderFactory of the Activity.

    java.lang.IllegalArgumentException: SavedStateProvider with the given key is already registered
        at androidx.savedstate.SavedStateRegistry.registerSavedStateProvider(SavedStateRegistry.java:111)
        at androidx.lifecycle.SavedStateHandleController.attachToLifecycle(SavedStateHandleController.java:50)
        at androidx.lifecycle.SavedStateHandleController.create(SavedStateHandleController.java:70)
        at androidx.lifecycle.AbstractSavedStateViewModelFactory.create(AbstractSavedStateViewModelFactory.java:67)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
        at androidx.compose.ui.viewinterop.ViewModelKt.get(ViewModel.kt:75)
        at androidx.compose.ui.viewinterop.ViewModelKt.viewModel(ViewModel.kt:60)

I had to move this code inside a NavHost Composable. I reported this on the KotlinLang Slack and was told this issue relates to #2152 . It uses the incorrect Scope for a Navigation Composable.

In the case of the related issue, the scope is too small and in my case, it is the exact opposite Problem.

In that issue I linked, the fragment is within the Navigation graph, so the issue is that the saved state is too small of a scope (the navigation graph encompasses multiple fragments). In your Compose case, the entire navigation graph in within the single Activity/Fragment, so there the scope is too large and you end up saving state multiple times with the same key.

Although the issue should be fixed by a more correct approach to scoping, it is still worth to file a bug for the inverse problem with saved state.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:4
  • Comments:19 (5 by maintainers)

github_iconTop GitHub Comments

14reactions
mitchtabiancommented, Jan 29, 2021

The hilt-navigation version 1.0.0-alpha03 is great. ViewModels are retained via the NavBackStackEntry now. Love it.

There’s still a limitation with building a “compose only” navigation system though. I will try to explain with an example.

Suppose you have a bottom nav with 3 items. You could easily implement that with something like this:

val navController = rememberNavController()
Scaffold(
    bottomBar = {
        BottomNav(navController)
    }
) {
    NavHost(navController = navController, startDestination = Home.route) {
        composable(route = Home.route) {
            HomeScreen()
        }
        composable(route = Profile.route) {
            ProfileScreen()
        }
        composable(route = Settings.route) {
            SettingsScreen()
        }
    }
}

nav demo

Navigating using the back button works great now (Data is persisted) since the ViewModel gets its ViewModelStoreOwner from the NavBackStackEntry. Horray.

The problem

But if you click on any of the entries a second time, the screen stacks. A new viewmodel is created since a new NavBackStackEntry is created.

2

Solution?

We need something to prevent the stacking of back stack entries. If an item is re-selected, it should be removed from its position in the stack and placed at the top. 3

launchSingleTop is great but only works if the entry is already at the top of the stack.

Thanks and sorry for the long post I probably should have created a feature request. One might already exists?

5reactions
danysantiagocommented, Jan 15, 2021

@Guimareshh, we have a scheduled release of the androidx.hilt artifacts on January 27th (if all goes well), sorry for the trouble. As the reference comment shows, there will be a hilt-navigation artifact you can use to get retrieve a ViewModel out of a NavBackStackEntry

You don’t have to switch to Hilt to make DI work with Compose, but Hilt still makes some things easier, such as App, Activity and Service injections along with ViewModel injection. Note that the functions in hilt-navigation scheduled for release will also let you use navigation-compose ViewModels which have more granular scopes.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Jetpack Compose: Adding a Hilt ViewModel to the Navigation ...
The app in question is an MVVM (Model-View-ViewModel) application that makes use of Hilt for dependency injection as well as the Jetpack Navigation...
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 >
Jetpack compose with Dagger/HILT, MVVM and NavController
Hi guys, today we are going to explore how we can use Jetpack compose in an application that has multiple screens and uses...
Read more >
How to inject a ViewModel into a composable function using ...
From version androidx.hilt:hilt-navigation-compose:1.0.0-alpha02 you can inject view model into Composable functions by:
Read more >
Android Compose UI: ViewModel + Hilt Dependency Injection
Hilt is built on top of the popular DI library Dagger to benefit from the compile-time correctness, runtime performance, scalability, and ...
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 Reddit Thread

No results found

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