【问题标题】:Android Databinding with LiveData - Validating multiple fields together使用 LiveData 的 Android 数据绑定 - 一起验证多个字段
【发布时间】:2019-09-13 19:42:51
【问题描述】:

我在 ViewModel 中使用带有 LiveData 的双向数据绑定来处理注册表单。

由于填写了字段,需要一起评估字段的有效性(以及整个表单),并且只有在一切正确时才启用提交按钮。

使用常规的 Observable 对象并使用 @Bindable 这将很简单,只需为所需的每个验证注释一个“getter”函数并执行必要的验证步骤并在每个函数内返回适当的结果。

但我正在使用 LiveData。我想出了一个使用MediatoLiveData 的解决方案(参见下面的基本示例),但在我看来应该有另一种,也许更好的方法。

class RegistrationViewModel : ViewModel() {
    val email: MutableLiveData<String> by lazy { MutableLiveData<String>() }

    val emailConf: MutableLiveData<String> by lazy { MutableLiveData<String>() }

    val emailValid: MediatorLiveData<Boolean> = MediatorLiveData()

    val emailChanged: (Any) -> Unit = cc@ {

        //Obviously there is more validation needed but this is just an example
        if (email.value != null && emailConf.value != null) {

            emailValid.value = email.value.isNotEmpty() && emailConf.value.isNotEmpty() && email.value == emailConf.value
            return@cc
        }

        emailValid.value = false
    }

    init {
        emailValid.addSource(email, emailChanged)
        emailValid.addSource(emailConf, emailChanged)
    }
}

例如,要将其绑定到 UI,按钮的 enabled 属性或标签的 visibility 属性可以适当地绑定到 emailValid 属性。

【问题讨论】:

  • 听起来你想“组合”多个 LiveData,就像我在 here 所做的那样。
  • 谢谢,但看起来你所做的正是我在这里所做的,只是在一定程度上抽象。我的问题真的是,是否有另一种我没有看到的方法。
  • 在那种情况下,“不是真的,不是”。

标签: android-databinding android-architecture-components android-livedata


【解决方案1】:

您的方法是正确的,但代码存在一些设计问题:

  • lazy 字段用于init 部分。字段变得不懒
  • emailValid 字段可以暴露为LiveData
  • 验证可以封装在内部类中,但不是必须的

    class RegistrationViewModel : ViewModel() {
        val email = MutableLiveData<String>()
        val emailConf = MutableLiveData<String>()
    
        @Suppress("UNCHECKED_CAST")
        val emailValid: LiveData<Boolean> = MediatorLiveData<Boolean>().apply {
            val validator = Validator(::postValue)
            addSource(email, validator as Observer<String>)
            addSource(emailConf, validator as Observer<String>)
        }
    
        private inner class Validator(private val validationConsumer: (Boolean) -> Unit) : Observer<Any> {
            override fun onChanged(ignored: Any?) {
                //Obviously there is more validation needed but this is just an example
                val email = email.value
                val emailConf = emailConf.value
                validationConsumer(when {
                    email.isNullOrEmpty() -> false
                    emailConf.isNullOrEmpty() -> false
                    email == emailConf -> true
                    else -> false
                })
            }
        }
    }
    

如果您需要一些繁重验证,您可以为emailValid隐藏可变字段,并在后台验证完成时手动更新它

【讨论】:

    猜你喜欢
    • 2018-05-23
    • 2017-07-25
    • 2023-02-15
    • 1970-01-01
    • 2020-08-24
    • 1970-01-01
    • 2014-03-26
    • 1970-01-01
    • 2020-07-22
    相关资源
    最近更新 更多