RecyclerView y DiffUtil – Una pesadilla de concurrencia
La documentación de DiffUtil
sugiere generar el DiffUtil.DiffResult
en un subproceso de fondo debido a posibles tiempos de cálculo largos. Esto parece una mala idea para mí, porque ese hilo podría estar funcionando con datos obsoletos en una situación como la siguiente (suponiendo que el acceso a la list
es seguro de subproceso):
- Agregar datos a la
list
y notificar al adaptador - Necesidad de reemplazar la
list
connewList
que tendría un diff de algunas adiciones y algunas remociones - Llame a
DiffUtil.calculateDiff
en segundo plano y obtenga elDiffResult
paralist
ynewList
y publique un mensaje en el subproceso principal que utilizaránewList
y llamaráDiffResult.dispatchUpdatesTo
- Antes de que se maneje ese mensaje, el usuario toma una acción en el hilo principal que hace que las mutaciones aparezcan en la
list
- El mensaje se maneja,
newList
se establece para ser el nuevo origen de datos yDiffResult.dispatchUpdatesTo
se ejecuta causando una vista inconsistente de los datos subyacentes + una pérdida de cualquier mutación desde elDiffResults
se calcularon
Bueno, eso no es bueno, así que cambiemos a partir del paso 3:
- ¿Cómo se puede agregar una línea de divisor en un Android RecyclerView?
- RecyclerVista el espacio entre los elementos que se expanden al desplazarse
- Cómo animar el cambio de un gestor de diseño de la vista de reciclador
- ¿Cómo evitar la reordenación de elementos en StaggeredGridLayoutManager después del cambio de orientación?
- Cómo obtener clics en RecyclerView (NO los niños)
- Establezca
newList
como el nuevo origen de datos, llame aDiffUtil.calculateDiff
en segundo plano y obtenga elDiffResult
paralist
ynewList
y publique un mensaje en el subproceso principal que llamaráDiffResult.dispatchUpdatesTo
- Antes de que se maneje ese mensaje, el usuario toma una acción en el subproceso principal que causa las mutaciones a
newList
, y notifica al adaptador, causando una vista inconsistente de los datos porqueDiffResult.dispatchUpdatesTo
no ha sido llamado aún
Hay más variaciones en esto, pero ninguno es bueno. Parece que la única manera de utilizar DiffUtil
forma fiable con un conjunto de datos grande y un conjunto de cambios es desactivar o poner en cola todas las actualizaciones hasta que se DiffResult.dispatchUpdatesTo
.
¿Me estoy perdiendo algo que haría lo anterior falso?
- RecyclerView desplazamiento horizontal desplazamiento en el centro
- Android RecyclerView con GridLayoutManager hace que el artículo abarque varias filas
- CardView dentro de RecyclerView tiene márgenes adicionales
- Detener el desplazamiento del usuario para establecer la posición en RecyclerView
- ¿Debo cambiar el Listview existente en mi aplicación a RecyclerView?
- ¿Hay alguna forma de calcular la posición final de desplazamiento
- Recyclerview Adaptador y Glide - misma imagen cada 4-5 filas
- Artículo de reciclaje
Echa un vistazo a BatchingListUpdateCallback. Es la clase, que se envuelve la devolución de llamada principal y cuando se produjo un cambio múltiple en la lista, el batchingListCallback notificará sólo una vez que la devolución de llamada principal.
https://developer.android.com/reference/android/support/v7/util/BatchingListUpdateCallback.html
EDITAR
Siento que mi respuesta no sea correcta.
Miré en el código fuente DiffUtil. Y veo, que el BatchingListUpdateCallback se utiliza en el método dispatchUpdatesTo
todos modos.
public void dispatchUpdatesTo(ListUpdateCallback updateCallback) { final BatchingListUpdateCallback batchingCallback; if (updateCallback instanceof BatchingListUpdateCallback) { batchingCallback = (BatchingListUpdateCallback) updateCallback; } else { batchingCallback = new BatchingListUpdateCallback(updateCallback); // replace updateCallback with a batching callback and override references to // updateCallback so that we don't call it directly by mistake //noinspection UnusedAssignment updateCallback = batchingCallback; }
Pero como vector para el camino correcto esto podría ser útil 🙂
Acabé apilando actualizaciones para gestionar la interacción del usuario durante los cálculos DiffUtil y todavía acceder a datos en el hilo principal sólo.
Lo escribí allí: https://geoffreymetais.github.io/code/diffutil-threading/
- Android SAF (Storage Access FrameWork): Obtenga un archivo Uri de TreeUri
- Aplicación Web de Android RESTful con Zend Framework