0

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)?

pierre.b
  • 13
  • 3

1 Answers1

0

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)
            ...
         }
     }
     ...
}
pierre.b
  • 13
  • 3