如何在 Compose Navigation 中导航视图模型字段更改?

How to navigate on view model field change in Compose Navigation?

在我的应用程序中,我想将信息发送到服务器,在收到成功响应后,我想将信息传递到当前屏幕以导航到另一个屏幕。

流程如下:

从 UI 我调用 viewModel 向服务器发送请求。在 ViewModel 我有一个回调:

@HiltViewModel
class CreateAccountViewModel @Inject constructor(
    private val cs: CS
) : ViewModel() {

    private val _screen = mutableStateOf("")

    val screen: State<String> = _screen

    fun setScreen(screen: Screen) {
        _screen.value = screen.route
    }

    private val signUpCallback = object : SignUpHandler {
        override fun onSuccess(user: User?, signUpResult: SignUpResult?) {
            setScreen(Screen.VerifyAccountScreen)
            Log.i(Constants.TAG, "sign up success")

        }

        override fun onFailure(exception: Exception?) {
            Log.i(Constants.TAG, "sign up failure ")
        }

    }
}

如您所见,我还 State 负责屏幕,因此当响应成功时,我想更新状态,以便 UI 层(屏幕)知道它应该导航到另一个屏幕。我的问题是:我怎样才能在

中观察 State
@Composable
fun CreateAccountScreen(
    navController: NavController,
    viewModel: CreateAccountViewModel = hiltViewModel()
) {
}

或者有更好的方法来实现吗?

我认为您的视图模型应该对导航路线一无所知。在这种情况下,简单的 verificationNeeded 标志就足够了:

var verificationNeeded by mutableStateOf(false)
    private set

private val signUpCallback = object : SignUpHandler {
    override fun onSuccess(user: User?, signUpResult: SignUpResult?) {
        verificationNeeded = true
        Log.i(Constants.TAG, "sign up success")
    }

    override fun onFailure(exception: Exception?) {
        Log.i(Constants.TAG, "sign up failure ")
    }
}

最佳做法是不在管理 NavHost 的视图之外共享 navController,并且只传递偶数处理程序。当您需要测试或预览屏幕时,它可能会有用。

以下是更改此标志后的导航方式:

@Composable
fun CreateAccountScreen(
    onRequestVerification: () -> Unit,
    viewModel: CreateAccountViewModel = hiltViewModel(),
) {
    if (viewModel.verificationNeeded) {
        LaunchedEffect(Unit) {
            onRequestVerification()
        }
    }
}

在您的导航管理视图中:

val navController = rememberNavController()
NavHost(
    navController = navController,
    startDestination = Screen.CreateAccount
) {
    composable(Screen.CreateAccount) {
        CreateAccountScreen(
            onRequestVerification = {
                navController.navigate(Screen.VerifyAccountScreen)
            }
        )
    }
}