Jetpack Compose 使用 SavedStateHandle 发送返回结果不适用于 ViewModel 中注入的 SavedStateHandle

Mal*_*lal 4 android android-jetpack-navigation android-jetpack-compose viewmodel-savedstate dagger-hilt

使用 SavedStateHandle 发送回结果不适用于 ViewModel 中注入的 SavedStateHandle。

使用navController.currentBackStackEntry?.savedStateHandle?它可以得到结果!

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")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在 ViewModel 中使用saveStateHandleHilt 注入不会得到结果!

@HiltViewModel
class CreatePostViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle,
) : ViewModel() {
    
    init {

        viewModelScope.launch {
            savedStateHandle.getStateFlow("result", "").collect {
                Timber.d("Result -> $it")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我将结果发送回前一屏幕的方式!

navController.previousBackStackEntry?.savedStateHandle?.set("result", "this is result")
Run Code Online (Sandbox Code Playgroud)

ian*_*ake 12

需要认识到的重要一点是,每个 ViewModel 实例都有自己的SavedStateHandle- 如果您在同一屏幕上访问两个单独的 ViewModel 类,它们将各自拥有自己的SavedStateHandle.

因此,当您调用时navController.currentBackStackEntry?.savedStateHandle,您实际上并没有获得SavedStateHandle与您关联的CreatePostViewModel- 如果您查看NavBackStackEntry源代码,您会注意到它SavedStateHandle返回的是一个私有 ViewModel 子类,该子类完全独立于您创建的任何其他 ViewModel。

因此,如果您想将结果专门发送回您自己的自定义 ViewModel(例如您的CreatePostViewModel),您需要在其他屏幕中专门请求该 ViewModel:

// Assumes `it` is the current NavBackStackEntry that was passed to you
// from the composable() lambda
val previousBackStackEntry = remember(it) {
  navController.previousBackStackEntry!!
}
val previousViewModel = hiltViewModel<CreatePostViewModel>(previouslyBackStackEntry)
previousViewModel.savedStateHandle?.set("result", "this is result")
Run Code Online (Sandbox Code Playgroud)

请注意,使用这种方法,您需要通过其确切的类名称专门询问 ViewModel - 这是因为类名称是key传递给viewModel()方法的默认名称,对于hiltViewModel().