Связывание данных Android с LiveData - проверка нескольких полей вместе - PullRequest
0 голосов
/ 07 марта 2019

Я использую двустороннюю привязку данных с LiveData внутри ViewModel для обработки формы регистрации.

Когда поля заполнены, есть поля, которые необходимо оценивать вместе на предмет достоверности (а также общей формы), и активировать кнопку «Отправить» можно только тогда, когда все правильно.

С обычным объектом 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)
    }
}

Например, чтобы связать его с пользовательским интерфейсом, свойство enabled кнопки или свойство visibility метки может быть соответствующим образом связано со свойством emailValid.

1 Ответ

1 голос
/ 22 марта 2019

Ваш подход правильный, но у кода есть некоторые проблемы с дизайном:

  • 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 и вручную обновить его после завершения проверки фона

...