Проблема поведения привязки данных Android в ObservableList

Мне трудно определить реальный смысл существования android.databinding.ObservableList как функция привязки данных.

Сначала это выглядело как классный инструмент для отображения списков посредством привязки данных, добавления их через xml к RecyclerView, Для этого я создал BindingAdapter следующим образом:

@BindingAdapter(value = {"items"}, requireAll = false)
public static void setMyAdapterItems(RecyclerView view, ObservableList <T> items) {
    if(items != null && (view.getAdapter() instanceof MyAdapter)) {
        ((GenericAdapter<T>) view.getAdapter()).setItems(items);
    }
}

Таким образом, я могу использовать атрибут app:items в RecyclerView с MyAdapter установить его, чтобы обновить его элементы.

Теперь лучшая особенность ObservableList это вы можете добавить OnListChangedCallback к нему, который обрабатывает те же события, доступные в RecyclerView добавить / переместить / удалить / изменить элементы в нем без перезагрузки всего списка.

Таким образом, логика, которую я думал реализовать, была следующей:

  1. Я начинаю с пустого MyAdapter
  2. Когда мои элементы извлекаются из моих API, я создаю экземпляр ObservableArrayList завернуть их и передать binding
  3. Привязка данных вызывает мой BindingAdapter передача предметов MyAdapter
  4. когда MyAdapter получает новые предметы, очищает старые и добавляет OnListChangedCallback к ObservableList получил обрабатывать микро-изменения
  5. Если что-то изменится в ObservableList, MyAdapter будет меняться соответственно без полного обновления
  6. Если я хочу отобразить совершенно другой набор элементов того же типа, я могу просто переустановить binding переменная, поэтому BindingAdapter будет вызван снова и MyAdapter элементы будут полностью изменены.

Например, если я хочу отображать элементы типа Game у меня есть два разных списка: "собственные игры" и "список желаний", я мог бы просто позвонить binding.setItems(whateverItems) чтобы полностью обновить отображаемые элементы, но, например, если я перемещу "список желаний" по списку, чтобы упорядочить их по релевантности, в каждом списке будут выполняться только микро-изменения без обновления всего объекта.

Оказывается, эта идея была неосуществима, потому что привязка данных повторно выполняет BindingAdapter каждый раз, когда производится одно изменение ObservableListТак, например, я наблюдаю за паром поведения:

  1. Я начинаю с пустого MyAdapter
  2. Когда мои элементы извлекаются из моих API, я создаю экземпляр ObservableArrayList завернуть их и передать binding
  3. Привязка данных вызывает мой BindingAdapter передача предметов MyAdapter
  4. когда MyAdapter получает новые предметы, очищает старые и добавляет OnListChangedCallback к ObservableList получил обрабатывать микро-изменения
  5. Если что-то изменится в ObservableList, BindingAdapter вызывается снова, таким образом, MyAdapter получает весь список снова и полностью обновляет.

Такое поведение кажется мне совершенно нарушенным, потому что ObservableList быть пригодным для использования в пределах данных xml, Я не могу серьезно выяснить законный случай, в котором такое поведение желательно.

Я посмотрел несколько примеров: вот и этот другой ТАК вопрос

В первой ссылке все примеры использовали ObservableList прямо к Adapter даже не передавая форму xml и фактическое связывание данных, в то время как в коде, связанном в ответе SO, разработчик сделал в основном то же самое, что я пытался сделать, добавив:

if (this.items == items){
        return;
}

в начале его Adapter.setItems(ObservableList<T> items) отбросить все случаи, когда метод вызывается из-за простых изменений в ObservableList,

Зачем нужно это поведение? В каких случаях такое поведение желательно? я чувствую ObservableList это функция, добавленная с привязкой данных, и она действительно полезна, за исключением случаев, когда используется с реальной привязкой данных, и в этом случае она заставляет вас защищаться от ее поведения. Если я объявлю это простым List в обоих xml теги данных и в BindingAdapter подпись, то я могу вернуть его ObservableList внутри MyAdapter и это работает просто отлично, но это довольно плохой взлом. Если бы это была просто отдельная функция от привязки данных, без запуска привязки при каждом изменении это было бы намного лучше, по моему мнению.

1 ответ

Решение

В соответствии с примером, представленным в документации https://developer.android.com/topic/libraries/data-binding/index.html, ObservableList используется для доступа к его элементам с помощью ключевого целого числа, то есть:

<data>
    <import type="android.databinding.ObservableList"/>
    <import type="com.example.my.app.Fields"/>
    <variable name="user" type="ObservableList&lt;Object&gt;"/>
</data>
…
<TextView
   android:text='@{user[Fields.LAST_NAME]}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

Поэтому, когда что-то меняется внутри ObservableList запускает BindingAdapter для обновления пользовательского интерфейса. Я думаю, что это основная цель использования ObservableList пока DataBinding находится в состоянии разработки. Возможно, в будущем DataBinding будет обновлен новым SomeObservableList который будет предназначен для использования в RecyclerView. Между тем, вы можете использовать if (this.items == items){return;} если это работает для вас, или пересмотреть вашу логику использования ObservableList,