Как я могу перебрать все представления, известные связующему данные?

#android #android-databinding

#Android #android-привязка данных

Вопрос:

У меня есть три TextInputEditText представления в моем макете, где пользователь может вводить определенную информацию.
По щелчку Button эта информация сохраняется в моей базе данных.

После того, как пользователь нажмет на это Button , я хочу очистить все TextInputEditText поля.
Прямо сейчас я делаю это с помощью жесткого кодирования:

 private fun clearAllEditTextFields() {
        
    Timber.d("clearAllEditTextFields: called")
        
    binding.bookTitleEditText.text = null
    binding.bookAuthorEditText.text = null
    binding.bookPageCountEditText.text = null
        
}
 

Поскольку это плохо, я хотел бы использовать динамический for each цикл для идентификации всех представлений TextInputEditText известного типа binding и очистки их содержимого:

 private fun clearAllEditTextFields() {
        
    Timber.d("clearAllEditTextFields: called")
        
    for (view in binding.views) {

        if (view is TextInputEditText) {

            view.text = null
        
        }

}
 

К сожалению, такого поля нет binding.views .
Есть ли еще способ добиться этого или чего-то с теми же свойствами?

Что я пробовал до сих пор

Я использовал BindingAdapter . В моем Util классе, куда идут все мои функции расширения, я создал EditText функцию расширения clearText , аннотированную как BindingAdapter и JvmStatic :

 @JvmStatic
@BindingAdapter("clearText")
fun EditText.clearText(@NotNull shouldClear: Boolean) {
        
    Timber.d("clearText: called")
        
    if (shouldClear) text = null
        
}
 

В XML:

 <com.google.android.material.textfield.TextInputEditText
    android:id="@ id/book_title_edit_text"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:imeActionId="100"
    android:imeOptions="actionNext"
    android:inputType="text"
    android:text="@={viewModel.bookTitle}"
    app:clearText="@{viewModel.clearAllEditTextFields}"
/>
 

В моем ViewModel классе я создал a var clearAllEditTextFields = false , который изменяется в clearAllEditTextFields() функции, которая вызывается внутри моего ViewModel :

 ...
var clearAllEditTextFields = false
clearAllEditTextFields()
...

private fun clearAllEditTextFields() {
        
    Timber.d("clearAllEditTextFields: called")
        
    clearAllEditTextFields = true
        
}
 

Согласно Logcat, моя функция расширения вызывается при ViewModel инициализации my. Однако при clearAllEditTextFields() вызове он не запускает новый вызов функции расширения.

Ответ №1:

for Не существует простого цикла для перебора представлений в binding объекте, и вы можете попробовать следующее, чтобы сохранить свой код в сознании.

Функции области видимости

     binding.apply{
       bookTitleEditText.text = null
       bookAuthorEditText.text = null
       bookPageCountEditText.text = null
    }
 

функции области видимости хороши, если просмотров мало, и в итоге мы получаем довольно большой boiler-plate код, если количество просмотров велико, и в этих случаях я думаю Binding-Adapter , что это был бы хороший выбор

 @BindingAdapter("clear_text")
fun EditText.clearText(shouldClear : Boolean?){
   shouldClear?.apply{
       if(shouldClear)
          text = null
   }
}
 

ViewModel

 private val _shouldClear = MutableLiveData<Boolean>()
val shouldClear : LiveData<Boolean>
get() = _shouldClear

fun setClearStatus(status : Boolean){
   _shouldClear.value = status
}

//since clearing a text is an event and not state, reset the clear_status once it's done
fun resetClearStatus(){
  _shouldClear.value = nul
}
 

XML

 <EditText 
  ......
  app:clear_text = "@{yourViewModel.shouldClear}"
  ...... />
 

ActivityClass

 ...
binding.lifecycleOwner = this
...


private fun clearAllEditTextFields() {
   yourViewModel.setClearStatus(true)
   yourViewModel.resetClearStatus()        
}

 

Редактировать:

добавьте binding.lifecycleOwner = this свой класс activity и используйте его для наблюдения за LiveData с привязкой данных. Представление будет отслеживать изменения текста во время выполнения.

Комментарии:

1. Спасибо за ответ. Функция области видимости также не является хорошей практикой, поскольку вам также приходится обновлять ее всякий раз, когда вы добавляете новое EditText . Ваш второй метод звучит хорошо, но он не работает, так как изменение shouldClear не вызывает вызова clearText() . Функция вызывается только один раз, когда макет раздувается.

2. возможно, что-то не так с вашей стороны, загрузите код того, что вы пробовали до сих пор

3. адаптер привязки получает уведомление каждый раз, когда изменяется базовое исходное значение

4. вы назначили lifecycleowner объекту привязки?

5. Нет, это JvmStatic то, для чего нужно. У меня есть это в моем Util классе, где я хотел бы его сохранить. И binding в этом классе нет.