Flow 不更新 Composable
Flow doesn't update Composable
我遇到了以下问题:
这是注册屏幕,上面有几个输入字段。当用户输入内容时,该值将传递给 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) }
)
}
}
在此先感谢您的帮助
你的问题是你正在改变你的状态,所以流程中使用的 equals 总是 returns 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))
}
}
在您的情况下,您的 MutableStateFlow
持有可变值的 link,这就是为什么当您传递 hashcode
(根据所有字段值计算)的值时相同的原因,流程不会更新值。
查看 Why is immutability important in functional programming?
data class
是一个很好用的工具,它将为您提供开箱即用的所有 copy
,但您应该使用 var
发出并且只使用 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)
}
}
}
我遇到了以下问题:
这是注册屏幕,上面有几个输入字段。当用户输入内容时,该值将传递给 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) }
)
}
}
在此先感谢您的帮助
你的问题是你正在改变你的状态,所以流程中使用的 equals 总是 returns 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))
}
}
在您的情况下,您的 MutableStateFlow
持有可变值的 link,这就是为什么当您传递 hashcode
(根据所有字段值计算)的值时相同的原因,流程不会更新值。
查看 Why is immutability important in functional programming?
data class
是一个很好用的工具,它将为您提供开箱即用的所有 copy
,但您应该使用 var
发出并且只使用 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)
}
}
}