0

我遇到了以下问题:

有注册屏幕,上面有几个输入字段。当用户输入内容时,该值将传递给 ViewModel,设置为屏幕状态并通过 StateFlow 传递回屏幕。从可组合中,我正在观察这个 StateFlow。问题是 Composable 在向 Flow 发送新值后不会失效。

这是 ViewModel 代码:

class RegistrationViewModel : BaseViewModel() {

    private val screenData = CreateAccountRegistrationScreenData.init()

    private val _screenDataFlow = MutableStateFlow(screenData)
    internal val screenDataFlow = _screenDataFlow.asStateFlow()

    internal fun updateFirstName(name: String) {
        screenData.firstName = name
        updateScreenData()
    }

    private fun updateScreenData() {
        viewModelScope.launch {
            _screenDataFlow.emit(screenData.copy())
        }
        println()

    }

}

这是可组合的代码:

@Composable
fun RegistrationScreen(navController: NavController, stepName: String) {
    val focusManager = LocalFocusManager.current

    val viewModel: RegistrationViewModel by rememberInstance()

    val screenData by viewModel.screenDataFlow.collectAsState()

    Scaffold {
        ConstraintLayout(
            modifier = Modifier
                .fillMaxSize()
                .pointerInput(Unit) {
                    detectTapGestures(onTap = {
                        focusManager.clearFocus()
                    })
                },
        ) {
            val (
                textTopLabel,
                textBottomLabel,
                tfFirstName,
                tfLastName,
                tfEmail,
                tfPassword,
                btnNext
            ) = createRefs()

            ...
            RegistrationOutlinedTextField(
                value = screenData.firstName ?: "",
                constraintAsModifier = {
                    constrainAs(tfFirstName) {
                        top.linkTo(textBottomLabel.bottom, margin = Padding30)
                        start.linkTo(parent.start)
                        end.linkTo(parent.end)
                    }
                },
                label = { Text("First Name", style = PoppinsNormalStyle14) },
                leadingIcon = {
                    Image(
                        painter = painterResource(id = R.drawable.ic_user_login),
                        contentDescription = null
                    )
                },
                onValueChange = { viewModel.updateFirstName(it) }
            )
    }
}

提前感谢您的帮助

4

2 回答 2

2

您的问题是您正在改变您的状态,因此流程中使用的 equals 始终返回 true。

改变这个

internal fun updateFirstName(name: String) {
    screenData.firstName = name
    updateScreenData()
}

private fun updateScreenData() {
    viewModelScope.launch {
        _screenDataFlow.emit(screenData.copy())
    }
    println()

}

internal fun updateFirstName(name: String) {
    viewModelScope.launch {
        _screenDataFlow.emit(screenData.copy(firstName = name))
    }
}
于 2021-11-28T18:21:14.320 回答
1

在您的情况下,您MutableStateFlow持有指向可变值的链接,这就是为什么当您传递hashcode相同的值(根据所有字段值计算)时,流程不会更新该值。

查看为什么不变性在函数式编程中很重要?

data class是一个很好的工具,它将为您提供所有copy开箱即用的工具,但您应该发出 usingvar并且仅val用于您的字段以避免错误。

此外,MutableStateFlow您始终可以访问value,因此您无需将其存储在单独的变量中:

class RegistrationViewModel : BaseViewModel() {

    private val _screenDataFlow = MutableStateFlow(CreateAccountRegistrationScreenData())
    internal val screenDataFlow = _screenDataFlow.asStateFlow()

    internal fun updateFirstName(name: String) {
        _screenDataFlow.update { screenData ->
            screenData.copy(firstName = name)
        }
    }
}
于 2021-11-29T00:38:13.987 回答