As described in this Android Developers article, yes, you can.
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)
}
}
}
}
To avoid writing all this code every time I need to share a ViewModel
between destinations, I devised a little function to do this for me:
@Composable
inline fun <reified T: ViewModel> NavBackStackEntry.viewModelScopedTo(route: String): T {
val navController = LocalNavController.current
val parentEntry = remember(this) { navController.getBackStackEntry(route) }
return hiltViewModel(parentEntry)
}
Where LocalNavController
is a Composition Local that provides NavHostController
for the entire app.
You can use the function like this:
navigation(
startDestination = AppScreen.Persons.route,
route = AppScreen.Persons.graphDestination
) {
composable(
route = AppScreen.Persons.route
) {
PersonsScreen(it.viewModelScopedTo(AppScreen.Persons.graphDestination))
}
composable(
route = AppScreen.AddEditPerson.route,
arguments = listOf(navArgument("id") {type = NavType.IntType})
) {
AddPerson(
viewModel = it.viewModelScopedTo(AppScreen.Persons.graphDestination)
)
}
}
Both PersonsScreen
and AddPerson
composables will receive the same instance of a ViewModel
.