Shared view model in android compose project while using Hilt for dependency injection?
Asked Answered
F

3

12

Anyone has any clue how to retain a shared view model object across different composables? I'm using hilt and injecting viewmodel instance using hilt in composable. Basically there are 3 screens which share same data and changes I want to share it and I'm thinking of sharing this data through a shared view model.

myViewModel: MyViewModel = hiltViewModel()

So how can i use this MyViewModel as shared view model?

Fleeman answered 19/5, 2022 at 11:25 Comment(2)
Does this answer your question?Tapia
@PylypDukhov thank you so much buddy for the help.. this answer was super helpfulFleeman
F
13

All you need is something like this to find the view model in your navigation back stack entry and pass it to next composable screen:

val backStackEntry = remember {
    navHostController.getBackStackEntry("first_screen_route_where_viewmodel_was_firstly_initialized")
}
val viewModel: MyViewModel = hiltViewModel(backStackEntry)

Now you have got the view model which is exactly at same state where you have left it in previous screens. Now you can use it as a shared view model. Thanks @Pylyp for guidance..

Fleeman answered 22/5, 2022 at 8:45 Comment(1)
Note that remember {navController.getBackStackEntry(parentId)} can cause crashes and now triggers a lint warning (more here). the solution is to use a the backStackEntry as a key to remember such as. remember(navBackStackEntry) {navController.getBackStackEntry(parentId)}Vandervelde
B
9

As per the official documentation:

If you need to retrieve the instance of a ViewModel scoped to navigation routes or the navigation graph instead, use the hiltViewModel composable function and pass the corresponding backStackEntry as a parameter:

import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.compose.getBackStackEntry

@Composable
fun MyApp() {
    NavHost(navController, startDestination = startRoute) {
        navigation(startDestination = innerStartRoute, route = "Parent") {
            // ...
            composable("exampleWithRoute") { backStackEntry ->
                val parentEntry = remember(backStackEntry) {
                    navController.getBackStackEntry("Parent")
                }
                val parentViewModel = hiltViewModel<ParentViewModel>(parentEntry)
                ExampleWithRouteScreen(parentViewModel)
            }
        }
    }
}
Brune answered 14/4, 2023 at 10:56 Comment(0)
H
1

According to @gabhor's answer you can create an extension function to avoid writing the same code everywhere.

@Composable
inline fun <reified T : ViewModel> NavBackStackEntry.sharedViewModel(navController: NavController): T {
    val navGraphRoute = destination.parent?.route ?: return hiltViewModel()
    val parentEntry = remember(this) {
        navController.getBackStackEntry(navGraphRoute)
    }

    return hiltViewModel(parentEntry)
}

Reference: https://github.dev/philipplackner/NestedNavigationGraphsGuide

Herndon answered 17/7, 2023 at 9:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.