Tengo un chat en mi aplicación y quiero que mi RV permanezca en la posición 0 cuando llegue el nuevo mensaje y la posición del primer elemento visible sea 0, pero los mensajes nuevos se agregan encima del visible actualmente, pero los elementos visibles permanecen a la vista para que el usuario tiene que desplazarse para ver el nuevo mensaje.
Mi adaptador se amplió desde RecyclerView.Adapter<RecyclerView.ViewHolder> y encontré una pequeña solución para hacerlo funcionar:
private suspend fun update(newItems: List<IChatItem>) { var recyclerViewState: Parcelable? = null if ((recyclerView?.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() == 0) { recyclerViewState = recyclerView?.layoutManager?.onSaveInstanceState() } val diffResult = withContext(Dispatchers.Default) { DiffUtil.calculateDiff(Diff(this.currentItems, newItems)) } diffResult.dispatchUpdatesTo(this) recyclerViewState?.let { recyclerView?.layoutManager?.onRestoreInstanceState(recyclerViewState) } } La cosa es guardar el estado de RV y después de que DiffUtil complete su trabajo, restaurarlo. Funcionó, pero ahora estoy tratando de implementar un nuevo adaptador y extender mi clase de adaptador desde ListAdapter porque inicia DiffUtil en otro hilo. Funciona bien, pero el problema es que no puedo implementar mi solución anterior aquí, simplemente no funciona.
Intenté lo siguiente:
override fun submitList(list: MutableList<IChatItem>?) { var recyclerViewState: Parcelable? = null if ((recyclerView?.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() == 0) { recyclerViewState = recyclerView?.layoutManager?.onSaveInstanceState() } super.submitList(list) recyclerViewState?.let { recyclerView?.layoutManager?.onRestoreInstanceState(recyclerViewState) } }Pero esto ya no funciona. ¿Alguien tiene una solución?
PD: Encontré esta pregunta: insertar elementos de RecyclerView en la posición cero: siempre manténgase desplazado hacia arriba , pero no creo que esta sea la mejor solución para agregar elementos invisibles vacíos en la lista del adaptador. ¿Alguna otra idea?
UPD : como pensé, debido a que este adaptador inicia DiffUtil en otro subproceso, restauró el estado de RV antes de que DiffUtil complete su trabajo. Este código funciona:
override fun submitList(list: List<IChatItem>?) { var recyclerViewState: Parcelable? = null if ((recyclerView?.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() == 0) { recyclerViewState = recyclerView?.layoutManager?.onSaveInstanceState() } super.submitList(list) recyclerViewState?.let { Handler().postDelayed( { recyclerView?.layoutManager?.onRestoreInstanceState(recyclerViewState) }, 1000 ) } }Pero ofc esto no es lo que quiero. ¿Hay alguna forma de detectar cuándo DiffUtil ha terminado con todo?
Puede usar RecyclerView.AdapterDataObserver() y manejar lo que necesita.
Cree su clase de escucha que implemente RecyclerView.AdapterDataObserver()
y en el constructor de su adaptador, llame a registerAdapterDataObserver (su oyente)
y luego manejar sus devoluciones de llamadas.