我正在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
属性。
答案 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
设置隐藏的可变字段,并在后台验证完成后手动对其进行更新