Android与LiveData的数据绑定-一起验证多个字段

时间:2019-03-07 04:05:47

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

我正在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属性。

1 个答案:

答案 0 :(得分: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设置隐藏的可变字段,并在后台验证完成后手动对其进行更新