make - recyclerview android kotlin
RecyclerView.Adapter.notifyItemChanged() nunca pasa la carga Ăștil a onBindViewHolder() (4)
¿Por qué no simplemente usar RecyclerView.Adapter.notifyItemChanged(int position)
los documentos parece un poco ambiguo al mencionar
RecyclerView.Adapter.notifyItemChanged(int position,Object payload)
El cliente puede opcionalmente pasar una carga útil para un cambio parcial. Estas cargas útiles se fusionarán y se pueden pasar a onBindViewHolder del adaptador (ViewHolder, int, List)
por lo tanto, no está garantizado que recibirá la Lista en su onBindViewHolder
Estoy intentando actualizar un ViewHolder
en un RecyclerView
sin ViewHolder
a ViewHolder
todo. De acuerdo con los documentos, debo hacer esto llamando a RecyclerView.Adapter.notifyItemChanged(int position, Object payload)
, donde payload
es un objeto arbitrario que se pasará a RecyclerView.Adapter.onBindViewHolder(VH holder, int position, List<Object> payloads)
, donde podré actualizar ViewHolder.
Pero cuando intento esto, onBindViewHolder
siempre recibe una lista vacía. Entre estas dos llamadas, se borra la lista interna de cargas útiles. Después de establecer puntos de interrupción en el código fuente de RecyclerView, esto sucede debido a una retransmisión, que eventualmente llama a RecyclerView.ViewHolder.clearPayload()
¿Alguien más ha logrado que esto funcione? ¿Se trata de un error en la biblioteca de soporte o es algo que he hecho para activar una retransmisión entre estas dos funciones?
Aquí está el seguimiento de la pila para cuando se borra la carga útil:
"<1> main@831692616832" prio=5 runnable
java.lang.Thread.State: RUNNABLE
at android.support.v7.widget.RecyclerView$ViewHolder.clearPayload(RecyclerView.java:8524)
at android.support.v7.widget.RecyclerView$ViewHolder.resetInternal(RecyclerView.java:8553)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4544)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4461)
at android.support.v7.widget.LayoutState.next(LayoutState.java:86)
at android.support.v7.widget.StaggeredGridLayoutManager.fill(StaggeredGridLayoutManager.java:1423)
at android.support.v7.widget.StaggeredGridLayoutManager.onLayoutChildren(StaggeredGridLayoutManager.java:610)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2847)
at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3145)
at android.view.View.layout(View.java:14289)
at android.view.ViewGroup.layout(ViewGroup.java:4562)
at android.support.v4.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:581)
at android.view.View.layout(View.java:14289)
at android.view.ViewGroup.layout(ViewGroup.java:4562)
at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
at android.view.View.layout(View.java:14289)
at android.view.ViewGroup.layout(ViewGroup.java:4562)
at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
at android.view.View.layout(View.java:14289)
at android.view.ViewGroup.layout(ViewGroup.java:4562)
at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
at android.view.View.layout(View.java:14289)
at android.view.ViewGroup.layout(ViewGroup.java:4562)
at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
at android.view.View.layout(View.java:14289)
at android.view.ViewGroup.layout(ViewGroup.java:4562)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
at android.view.View.layout(View.java:14289)
at android.view.ViewGroup.layout(ViewGroup.java:4562)
at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1043)
at android.view.View.layout(View.java:14289)
at android.view.ViewGroup.layout(ViewGroup.java:4562)
at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
at android.view.View.layout(View.java:14289)
at android.view.ViewGroup.layout(ViewGroup.java:4562)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
at android.view.View.layout(View.java:14289)
at android.view.ViewGroup.layout(ViewGroup.java:4562)
at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
at android.view.View.layout(View.java:14289)
at android.view.ViewGroup.layout(ViewGroup.java:4562)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
at android.view.View.layout(View.java:14289)
at android.view.ViewGroup.layout(ViewGroup.java:4562)
at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
at android.view.View.layout(View.java:14289)
at android.view.ViewGroup.layout(ViewGroup.java:4562)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1976)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1730)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1004)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5481)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
at android.view.Choreographer.doCallbacks(Choreographer.java:562)
at android.view.Choreographer.doFrame(Choreographer.java:532)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Method.java:-1)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(NativeStart.java:-1)
En algunos casos, funcionó con notifyItemRangeChanged(getItemRealCount(), 1)
.
Si utiliza el animador de elementos (de forma predeterminada, está habilitado), la carga útil estará siempre vacía. Mira esta respuesta en el tracker de Android :
Así es como se diseña la carga útil del trabajo. Solo se pasa a on bind "si estamos volviendo a enlazar con el mismo titular de vista". Lo mismo para el enlace de datos, si no está vinculado al mismo titular de vista, no puede hacer el enlace de forma incremental. En el caso de animaciones de cambio, RV crea dos copias de la Vista para el fundido cruzado, de modo que no esté enlazado con el mismo VH en el postLayout.
Pronto, proporcionaremos una API para ejecutar animaciones de cambio dentro del mismo ViewHolder.
Por lo tanto, hasta que compartan esta nueva API, necesitamos usar algo como esto:
mRecyclerView.setItemAnimator(null);
editar: vea el comentario de @blindOSX, donde se dio cuenta de que para habilitar las cargas útiles, solo puede deshabilitar las animaciones de eventos de cambio de elementos.
edit2: Parece que han actualizado este comportamiento sin previo aviso. Ver respuesta actualizada @Patricia Li .
RecyclerView
crea de forma predeterminada otra copia de ViewHolder
para que las vistas se ViewHolder
entre sí. Esto causa el problema porque el antiguo ViewHolder
obtiene la carga útil, pero luego el nuevo no. Así que necesitas decirle explícitamente que reutilice el anterior:
DefaultItemAnimator animator = new DefaultItemAnimator() {
@Override
public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
return true;
}
};
mRecyclerView.setItemAnimator(animator);