android android-recyclerview android-databinding observablelist android-binding-adapter

Cuestión de comportamiento de ObservableList de enlace de datos de Android



android-recyclerview android-databinding (1)

Me resulta difícil detectar la razón de ser real de android.databinding.ObservableList como una función de enlace de datos.

Al principio, parecía una herramienta genial para mostrar listas, a través del enlace de datos , y agregarlas a través de xml a un RecyclerView . Para hacerlo, hice un BindingAdapter como este:

@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); } }

De esta forma, puedo usar la app:items atributos app:items en un RecyclerView con un conjunto de parámetros MyAdapter , para actualizar sus elementos.

Ahora, la mejor característica de ObservableList es que puede agregarle un OnListChangedCallback , que maneja los mismos eventos disponibles en RecyclerView para agregar / mover / eliminar / cambiar elementos sin tener que volver a cargar toda la lista.

Entonces la lógica que pensé implementar fue el siguiente:

  1. Comienzo con un MyAdapter vacío
  2. Cuando mis elementos se extraen de mis API, instancia un ObservableArrayList envolviéndolos y pasándolos al binding
  3. El enlace de datos invoca mi BindingAdapter pasando los elementos a MyAdapter
  4. Cuando MyAdapter recibe nuevos elementos, borra los antiguos y agrega un OnListChangedCallback a la ObservableList recibida para manejar OnListChangedCallback
  5. Si algo cambia en la MyAdapter ObservableList , MyAdapter cambiará en consecuencia sin actualizar completamente
  6. Si quiero mostrar un conjunto completamente diferente del mismo tipo de elementos, puedo simplemente volver a establecer la variable de binding , por lo que se invocará de nuevo el MyAdapter y los elementos de MyAdapter cambiarán por completo.

Por ejemplo, si quiero mostrar elementos de tipo Game que tengo dos listas diferentes para "juegos propiedad" y "juegos de lista de deseos", podría simplemente llamar a binding.setItems(whateverItems) para actualizar completamente los elementos mostrados, pero por ejemplo , si muevo los "juegos de lista de deseos" por la lista para organizarlos por relevancia, solo se realizarán microcambios dentro de cada lista sin actualizar todo.

Resulta que esta idea era inviable porque el enlace de datos vuelve a ejecutar el BindingAdapter cada vez que se realiza un cambio en una ObservableList , por lo que, por ejemplo, observo el siguiente comportamiento:

  1. Comienzo con un MyAdapter vacío
  2. Cuando mis elementos se extraen de mis API, instancia un ObservableArrayList envolviéndolos y pasándolos al binding
  3. El enlace de datos invoca mi BindingAdapter pasando los elementos a MyAdapter
  4. Cuando MyAdapter recibe nuevos elementos, borra los antiguos y agrega un OnListChangedCallback a la ObservableList recibida para manejar OnListChangedCallback
  5. Si algo cambia en el ObservableList , el BindingAdapter se invoca de nuevo, por lo tanto, MyAdapter recibe toda la lista de nuevo y se actualiza completamente.

Este comportamiento me parece bastante malo porque impide que la ObservableList sea ​​utilizable dentro de un xml datos enlazados. No puedo entender seriamente un caso de fiar en el que este comportamiento sea deseable.

Busqué algunos ejemplos: aquí y esta otra pregunta SO

En el primer enlace, todos los ejemplos usaron la ObservableList directamente en el Adapter sin pasar el formulario xml y el enlace de datos real, mientras que en el código vinculado en la respuesta SO, el desarrollador hizo básicamente lo mismo que yo intenté, agregando:

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

al comienzo de su Adapter.setItems(ObservableList<T> items) para descartar todos los casos en que se invoca el método debido a cambios simples en la ObservableList .

¿Cuál es la necesidad de este comportamiento? ¿Cuáles podrían ser algunos casos en los que este comportamiento es deseable? Siento que ObservableList es una función que se agrega al enlace de datos y es muy útil, excepto cuando se utiliza con el enlace de datos real, en cuyo caso te obliga a defenderte de su comportamiento. Si lo declaro como una simple List en ambas etiquetas de datos xml y en la firma BindingAdapter , entonces puedo volver a MyAdapter a ObservableList dentro de MyAdapter y funciona bien, pero este es un hack bastante malo. Si fuera solo una característica separada del enlace de datos, sin activar el enlace en cada cambio, hubiera sido mucho mejor en mi opinión.


De acuerdo con el ejemplo provisto en los documentos https://developer.android.com/topic/libraries/data-binding/index.html#observable_collections, la ObservableList se utiliza para acceder a sus elementos utilizando un entero clave, es decir:

<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"/>

Por lo tanto, cuando se cambia algo dentro de la Lista ObservableList se activa BindingAdapter para actualizar la IU. Creo que ese es el objetivo principal de usar ObservableList por ahora mientras DataBinding está en estado de desarrollo. Quizás en el futuro DataBinding se actualice con una nueva SomeObservableList que se utilizará en RecyclerView. Mientras tanto, puede usar if (this.items == items){return;} si le resulta if (this.items == items){return;} o reconsiderar su lógica de uso de ObservableList .