Sending Result Back with SavedStateHandle does not work with SavedStateHandle injected in ViewModel.
Getting result using navController.currentBackStackEntry?.savedStateHandle? it works!
fun CreatePostScreen(
navController: NavController,
coroutineScope: CoroutineScope,
snackbarState: SnackbarHostState,
viewModel: CreatePostViewModel = hiltViewModel(),
) {
LaunchedEffect(key1 = Unit) {
navController.currentBackStackEntry?.savedStateHandle?.getStateFlow(
"result", ""
)?.collect { result ->
Timber.d("Result -> $result")
}
}
}
Using saveStateHandle injected using Hilt in ViewModel doesn't get the result!
@HiltViewModel
class CreatePostViewModel @Inject constructor(
private val savedStateHandle: SavedStateHandle,
) : ViewModel() {
init {
viewModelScope.launch {
savedStateHandle.getStateFlow("result", "").collect {
Timber.d("Result -> $it")
}
}
}
}
That's how I'm sending the result back to the previous screen!
navController.previousBackStackEntry?.savedStateHandle?.set("result", "this is result")
The important thing to realize is that every ViewModel instance gets its own
SavedStateHandle- if you accessed two separate ViewModel classes on the same screen, they would each have their ownSavedStateHandle.So when you call
navController.currentBackStackEntry?.savedStateHandle, you aren't actually getting theSavedStateHandleassociated with yourCreatePostViewModel- if you look at theNavBackStackEntrysource code, you'll note that theSavedStateHandleit is returning is for a private ViewModel subclass that is completely independent of any other ViewModels you create.Therefore if you want to send a result back specifically to your own custom ViewModel (like your
CreatePostViewModel), you need to specifically ask for exactly that ViewModel in your other screen:Note that with this approach, you need to specifically ask for the ViewModel by its exact class name - that's because the class name is the default
keythat is passed to theviewModel()method and similarly forhiltViewModel().