android Composable未在StateFlow中收集更新的值

oxalkeyp  于 2023-06-20  发布在  Android
关注(0)|答案(2)|浏览(181)

我用Compose编写了一个表单屏幕,用户可以在其中填写一些TextField并提交它。如果他们在填写字段之前按下提交按钮,空TextField s的支持文本将更改为“Required”。
Required text on empty fields
为此,我创建了一个包含showRequired字段的ViewState

  1. data class ViewState(
  2. showRequired: Boolean = false,
  3. // other fields
  4. )

在我的视图模型中,我创建了一个MutableStateFlow,并将ViewState作为其默认值:

  1. private val _viewState: MutableStateFlow<ViewState> = MutableStateFlow(ViewState())
  2. val viewState: StateFlow<viewState> = _viewState.asStateFlow()

为了让组合显示所需的消息,我像这样更新视图状态:

  1. fun onSubmitClicked(form: Form) {
  2. if (areRequiredFieldsMissing(form)) {
  3. _viewState.update { it.copy(showRequired = true) }
  4. }
  5. }

在我的composable中,我使用collectAsStateWithLifecycle()收集该流,然后在显示消息之前检查showRequired = true是否为:

  1. val viewState = viewModel.viewState.collectAsStateWithLifecycle()
  2. if (viewState.value.showRequired) {
  3. // set supportingText = Required
  4. }

当我单击提交按钮时,消息按预期显示。但是,如果我离开这个屏幕,然后再回到它,所需的消息会默认显示,而不是隐藏。我想我可以通过在按下后退按钮设置showRequired = false时更新视图状态来解决这个问题:

  1. // in my view model
  2. fun onBackPressed() {
  3. _viewState.update { it.copy(showRequired = false) }
  4. }

然而,这并不能解决任何问题。当我返回表单屏幕时,默认情况下仍显示所需的消息。当我调试组合时,为showRequired收集的值仍然为true。为什么将其更新为false不能正常工作,而在单击提交按钮时将其更新为true却可以?我想我误解了StateFlow的工作原理,但我不确定该尝试什么。
编辑:我通过在退出屏幕时重置我的ViewState来解决这个问题,这样showRequired就被重置为false,而不仅仅是更新它。

  1. _viewState.value = ViewState()
wz1wpwve

wz1wpwve1#

showRequired应该是一个单独的SharedFlow,不应该像StateFlow一样保持状态,当提交时有一个空字段时显示消息是一个事件而不是一个状态,你应该只显示一次。StateFlow保持其值,当您从不同的屏幕返回时,会发生重新组合

  1. val viewState = viewModel.viewState.collectAsStateWithLifecycle()
  2. if (viewState.value.showRequired) {
  3. // show message
  4. }

此代码块再次执行,并且由于showRequired in state is set true,因此将显示消息。
您应该从viewState中删除showRequired

  1. private val _formWarningEvent = MutableSharedFlow<Boolean>()
  2. val formWarningEvent = _formWarningEvent.asSharedFlow()

在Composable中

  1. LaunchedEffect(Unit) {
  2. viewModel.formWarningEvent.onEach { show -> // can register lifecycle or use collect etc.
  3. if (show) // show message
  4. }
  5. }
展开查看全部
wlsrxk51

wlsrxk512#

这是我对用例的理解。
如果不完全相同,请添加注解。
您有一个包含多个TextFields和一个Submit Button的屏幕。单击提交按钮后,应用程序将导航到另一个屏幕。
状态在屏幕之间的共享ViewModel中维护。错误消息仅在用户单击按钮但验证失败后显示。
我的第一个建议是使用屏幕级别的ViewModel,而不是共享的ViewModel,它会在删除时自动清除状态。
但是,可能存在不可能的情况。这样的话,你可以试试这个

    • 视图模型**
  1. // To store the state of the TextField input
  2. private val _textFieldState: MutableStateFlow<String> = MutableStateFlow("")
  3. val textFieldState: StateFlow<String> = _viewState.asStateFlow()
  4. // To store the state of the CTA button click
  5. private val _ctaClicked: MutableStateFlow<Boolean> = MutableStateFlow(false)
  6. val ctaClicked: StateFlow<Boolean> = _viewState.asStateFlow()
  7. // To store the state of the CTA button click
  8. private val textFieldErrorState: MutableStateFlow<String?> = combine(
  9. textFieldState,
  10. ctaClicked,
  11. ) { textFieldState, ctaClicked, ->
  12. if (ctaClicked && textFieldState.isEmpty()) {
  13. "Required"
  14. } else {
  15. null
  16. }
  17. }

我们使用Kotlin的combine来监听TextField输入状态和CTA按钮点击状态。
离开屏幕导航时,应重置ctaClicked
如果这对您的用例不起作用,请提供更多细节。

展开查看全部

相关问题