Проблема поведения привязки данных 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
добавить / переместить / удалить / изменить элементы в нем без перезагрузки всего списка.
Таким образом, логика, которую я думал реализовать, была следующей:
- Я начинаю с пустого
MyAdapter
- Когда мои элементы извлекаются из моих API, я создаю экземпляр
ObservableArrayList
завернуть их и передатьbinding
- Привязка данных вызывает мой
BindingAdapter
передача предметовMyAdapter
- когда
MyAdapter
получает новые предметы, очищает старые и добавляетOnListChangedCallback
кObservableList
получил обрабатывать микро-изменения - Если что-то изменится в
ObservableList
,MyAdapter
будет меняться соответственно без полного обновления - Если я хочу отобразить совершенно другой набор элементов того же типа, я могу просто переустановить
binding
переменная, поэтомуBindingAdapter
будет вызван снова иMyAdapter
элементы будут полностью изменены.
Например, если я хочу отображать элементы типа Game
у меня есть два разных списка: "собственные игры" и "список желаний", я мог бы просто позвонить binding.setItems(whateverItems)
чтобы полностью обновить отображаемые элементы, но, например, если я перемещу "список желаний" по списку, чтобы упорядочить их по релевантности, в каждом списке будут выполняться только микро-изменения без обновления всего объекта.
Оказывается, эта идея была неосуществима, потому что привязка данных повторно выполняет BindingAdapter
каждый раз, когда производится одно изменение ObservableList
Так, например, я наблюдаю за паром поведения:
- Я начинаю с пустого
MyAdapter
- Когда мои элементы извлекаются из моих API, я создаю экземпляр
ObservableArrayList
завернуть их и передатьbinding
- Привязка данных вызывает мой
BindingAdapter
передача предметовMyAdapter
- когда
MyAdapter
получает новые предметы, очищает старые и добавляетOnListChangedCallback
кObservableList
получил обрабатывать микро-изменения - Если что-то изменится в
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<Object>"/>
</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
,