Very similar to this issue but with a slight difference: Scoping States in Jetpack Compose
I have a scoped viewModel in a navigation graph. I can retrieve it but I do not find an elegant way of retrieving parameters ...
NavHost(navController, ...) {
...
composable(routeWithParameter) {
// (A): here, I need an 'args' parameter from route.
// My current solution is to 'add again' the parameter:
val args = it.arguments?.getString("argumentKey") // retrieve 'args' from route
val state = it.getRememberedParent(navController) // get parent
state.arguments?.putString("argumentKey", args ) // add again the 'args' in parent state
val viewModel = hiltViewModel<TViewModel>(state)
Log.d("MISC", "id =${System.identityHashCode(viewModel)}") // same instance as (B)
...
}
composable(route) {
// (B):
val viewModel = hiltViewModel<TViewModel>(it.getRememberedParent(navController))
Log.d("MISC", "id =${System.identityHashCode(viewModel)}") //same instance as (A)
...
}
...
}
@Composable
fun NavBackStackEntry.getRememberedParent(navController: NavHostController): NavBackStackEntry {
val parentId = this.destination.parent!!.id
return remember(this) { navController.getBackStackEntry(parentId) }
}
In the view model, parameters are retrieved using SavedStateHandle like this:
@HiltViewModel
class EditFarmViewModel @Inject constructor(
state: SavedStateHandle,
) : ViewModel() {
private val _args = checkNotNull(state.get<String>("argumentKey"))
In order to get the same viewModel instance in (A) and (B), I cannot build viewModel (A) by simply using hiltViewModel() without state as it leads to another instance beeing created for (B)...
I haven't found any trick in the doc (https://developer.android.com/jetpack/compose/libraries#hilt)
=> How to retrieve route parameters for (A) without re-inserting them?
OR
=> How to get the same scoped instance without using the getBackStackEntry to find parent in (A) (and so, use the initial route parameters)?
In fact, the error was I had to create a nested graph to access shared scope viewmodel composable and give the navigation parameter to the nested graph root.
like this:
NavHost(navController, ...) {
// => NESTED Navigation graph HERE that is the only one with arguments
navigation(route = routeWithParameters, startDestination = nestedrouteA
){
composable(nestedrouteA) {
val state = it.getRememberedParent(navController) // get parent
val viewModel = hiltViewModel<TViewModel>(state)
Log.d("MISC", "id =${System.identityHashCode(viewModel)}") // same instance as (B)
...
}
composable(nestedrouteB) {
// (B):
val viewModel = hiltViewModel<TViewModel>(it.getRememberedParent(navController))
Log.d("MISC", "id =${System.identityHashCode(viewModel)}") //same instance as (A)
...
}
}
...
}