RecyclerView: Inconsistencia detectada. Posición de artículo inválida

271

Nuestro control de calidad ha detectado un error: al girar el dispositivo Android (Droid Turbo), se produjo el siguiente bloqueo relacionado con RecyclerView :

java.lang.IndexOutOfBoundsException: Inconsistencia detectada. Posición de elemento no válida 2 (desplazamiento: 2). Estado: 3

Para mí, parece un error interno dentro de RecyclerView, ya que no puedo pensar en ninguna forma de que esto sea causado directamente por nuestro código ...

¿Alguien ha encontrado este problema?

¿Cuál sería la solución?

Una solución brutal podría ser quizás detectar la excepción cuando sucede y volver a crear la instancia de RecyclverView desde cero, para evitar quedarse con un estado corrupto.

Pero, si es posible, me gustaría entender mejor el problema (y quizás solucionarlo en su origen), en lugar de enmascararlo.

El error no es fácil de reproducir, pero es fatal cuando ocurre.

El seguimiento completo de la pila:

W/dalvikvm( 7546): threadid=1: thread exiting with uncaught exception (group=0x41987d40)
    E/AndroidRuntime( 7546): FATAL EXCEPTION: main
    E/AndroidRuntime( 7546): Process: com.oblong.mezzedroid, PID: 7546
    E/AndroidRuntime( 7546): java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 2(offset:2).state:3
    E/AndroidRuntime( 7546):    at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3382)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3340)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1810)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1306)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1269)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:523)
    E/AndroidRuntime( 7546):    at org.liboid.recycler_view.RecyclerViewContainer$LiLinearLayoutManager.onLayoutChildren(RecyclerViewContainer.java:179)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:1942)
    E/AndroidRuntime( 7546):    at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:2237)
    E/AndroidRuntime( 7546):    at org.liboid.recycler_view.LiRecyclerView.onLayout(LiRecyclerView.java:30)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
    E/AndroidRuntime( 7546):    at com.oblong.mezzedroid.workspace.content.bins.BinsContainerLayout.onLayout(BinsContainerLayout.java:22)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
    E/AndroidRuntime( 7546):    at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
    E/AndroidRuntime( 7546):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
    E/AndroidRuntime( 7546):    at android.view.View.layout(View.java:14946)
    E/AndroidRuntime( 7546):    at android.view.ViewGroup.layout(ViewGroup.java:4651)
    E/AndroidRuntime( 7546):    at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2132)
    E/AndroidRuntime( 7546):    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1872)
    E/AndroidRuntime( 7546):    at andro
KarolDepka
fuente
2
Una pregunta: ¿Qué tan consistente es tu repro? Sé que esto es un error en el código de Google aquí y aquí . Pero esto se puede evitar. Entonces, ¿está sucediendo esto en cada rotación?
VicVu
Hola. Ocurre solo raramente, pero cuando sucede, es fatal para la aplicación.
KarolDepka
Gracias por los enlaces a los errores. El primero parece más relevante que el segundo.
KarolDepka
1
Sí, creo que lo mejor es no permitir cambios en la vista de lista durante la rotación.
VicVu
1
Si pudiera reproducir fácilmente, sugeriría imprimir el valor de 'getItemCount' antes de todas las llamadas para 'notificar *' ... puede descubrir que el recuento de elementos no coincide con sus suposiciones.
Rich Ehmer

Respuestas:

209

Tuve un problema (posiblemente) relacionado: ingresar una nueva instancia de una actividad con un RecyclerView, pero con un adaptador más pequeño estaba desencadenando este bloqueo para mí.

RecyclerView.dispatchLayout()puede intentar extraer elementos de la chatarra antes de llamar mRecycler.clearOldPositions(). La consecuencia es que estaba extrayendo elementos del grupo común que tenían posiciones más altas que el tamaño del adaptador.

Afortunadamente, solo hace esto si PredictiveAnimationsestá habilitado, por lo que mi solución fue subclasificar GridLayoutManager( LinearLayoutManagertiene el mismo problema y 'arreglar') y anular supportsPredictiveItemAnimations()para devolver falso:

/**
 * No Predictive Animations GridLayoutManager
 */
private static class NpaGridLayoutManager extends GridLayoutManager {
    /**
     * Disable predictive animations. There is a bug in RecyclerView which causes views that
     * are being reloaded to pull invalid ViewHolders from the internal recycler stack if the
     * adapter size has decreased since the ViewHolder was recycled.
     */
    @Override
    public boolean supportsPredictiveItemAnimations() {
        return false;
    }

    public NpaGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public NpaGridLayoutManager(Context context, int spanCount) {
        super(context, spanCount);
    }

    public NpaGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
        super(context, spanCount, orientation, reverseLayout);
    }
}
Kas Hunt
fuente
44
Esto funcionó para mí, y deshabilitar las animaciones predictivas no hace que pierdas las animaciones por completo. Bravo.
Robert Liberatore
8
¡Muchas gracias señor! Trabajé instantáneamente con LinearLayoutManager, probablemente ahorrándome días.
levavare
8
Muchas gracias. Esta solución se trabaja con LinearLayoutManager.
Pruthviraj
8
Creo que este tipo merece que construyamos una estatua en honor a su preciosa ayuda ... Es uno de los peores problemas documentados en la web, pero parece que muchos desarrolladores se encuentran con este problema ... Me pregunto cómo descubrieron que podría se omitirá si PredictiveAnimations es falso, @KasHunt? Porque, el stacktrace no está muy claro ...
PAD
44
Alguien sabe, ¿cómo solucionarlo sin este truco? Debido a que notifyDatasetChanged se eliminó a favor de DiffUtil
Anton Shkurenko el
83

En mi caso (borrar / insertar datos en mi estructura de datos) ¡necesitaba borrar el grupo de reciclaje y luego notificar que el conjunto de datos cambió!

mRecyclerView.getRecycledViewPool().clear(); mAdapter.notifyDataSetChanged();

MatejC
fuente
66
Normalmente no digo esto, PERO MUCHAS GRACIAS. He intentado TODO para solucionar este bloqueo que ocurre esporádicamente cuando muevo un montón de elementos en la lista en orden rápido. He pasado literalmente probablemente una semana completa tratando de resolver este problema. Me alejé de él durante un par de meses para tratar de darle a mi cerebro la oportunidad de abordarlo de manera diferente, luego lo encontré en mi primer intento de Google. ¡Salud!
Chantell Osejo
Déjame conseguirte un montón de cookies porque te mereces cada una de ellas. Gracias.
antonis_st
¿Por qué tienes que hacer esto?
Dabluck
9
Esa es una operación bastante pesada que derrota el propósito de reciclar vistas.
gjsalot
@gjsalot Entonces, si uso esto, ¿puede causar algunos problemas?
Sreekanth Karumanaghat
38

Use en su notifyDataSetChanged()lugar notifyItem...en este caso.

Khaintt
fuente
55
En algunos casos, este es el camino a seguir. Tuve una situación en la que reemplacé todos mis artículos, pero no estaba siendo honesto con el adaptador, solo le dije que había insertado algunos artículos nuevos (notifyItemRangeInserted), sin decir primero que también había eliminado los artículos. El adaptador esperaba que hubiera más elementos de los que realmente había. Si utiliza cualquiera de los métodos de notificación del adaptador, espere notifyDataSetChanged, como notifyItemRangeRemoved / Inserted / Updated, la persona que llama tiene la responsabilidad total de decirle al adaptador exactamente lo que se modificó, o puede terminar con este "estado inconsistente".
JHH
19
Esto no es una solución en absoluto.
Miha_x64
Esa no es la forma de ir. Si esto funciona, significa que acaba de estropear el rango notifyItem...y corregirlo, que comenzará a funcionar en lugar de volver a representar todos los elementos.
Ranjan
12

Resolví esto retrasando la mRecycler.setAdapter(itemsAdapter)caja registradora después de agregar todos los elementos al adaptador mRecycler.addAll(items)y funcionó. No tengo idea de por qué lo hice para empezar, fue desde el código de una biblioteca que miré y vi esas líneas en el "orden incorrecto", estoy bastante seguro de que es así, por favor, si alguien puede confirmarlo, explique por qué ¿entonces? No estoy seguro si esta es una respuesta válida incluso

Odaym
fuente
Creo que esta es la solución, una vez que retrasé el adaptador, estaba bien, creo ... ahora aparece cuando se configura el adaptador en el hilo de la interfaz de usuario y se le agregan elementos.
EngineSense
18
Utilicé en swapAdapter(adapter, true)lugar de setAdapter(adapter)y ayudó.
frangulyan
11

Tuve un problema similar pero no exactamente el mismo. En mi caso, en 1 punto estaba borrando la matriz que se pasó a la vista del reciclador

mObjects.clear();

y no llamar a notifyDataSetChanged, ya que no quería que la vista del reciclador borrara inmediatamente las vistas. Estaba rellenando la matriz de mObjects en AsyncTask.

Aalap
fuente
9

Tuve el mismo problema con recyclerView, así que acabo de notificar al adaptador sobre el cambio del conjunto de datos justo después de que se borre la lista.

mList.clear();
mAdapter.notifyDataSetChanged();

mList.addAll(newData);
mAdapter.notifyDataSetChanged();
Reza
fuente
1
Este simple error me hizo perder mucho tiempo, ¡muchas gracias!
leb1755
7

Tengo el mismo problema. Ocurrió cuando me desplazaba rápido y llamaba a API y actualizaba los datos. Después de intentar todo para evitar un bloqueo, encontré la solución.

mRecyclerView.stopScroll();

Funcionará.

Anand Savjani
fuente
Esta es una solución, no una solución. Lo estás obligando a detener el desplazamiento. Mala
experiencia de usuario
1
@ Dr.aNdRO: el adaptador debe establecer la posición y si continúa desplazándose por la vista del reciclador, el adaptador no puede establecer los datos que son la causa del bloqueo. No está mal UX
Anand Savjani
1
tener sentido. Detener el desplazamiento no es un mal ux ya que la actualización de datos está sucediendo.
Sush
6

Estoy alterando los datos para RecyclerViewel fondo Thread. Tengo lo mismo Exceptionque el OP. Agregué esto después de cambiar los datos:

myRecyclerView.post(new Runnable() {
    @Override
    public void run() {
        myRecyclerAdapter.notifyDataSetChanged();
    }
});

Espero eso ayude

kashyap jimuliya
fuente
¡gracias hombre! Esta es la única respuesta que tiene sentido desde el punto de vista del desarrollo de Android.
user347187
Si bien también he resuelto con la ayuda de view.recycler_view.post, solía notifyItemInserted. En mi caso, ya ha sido hilo de la interfaz de usuario.
CoolMind
6

Este error ocurre cuando la lista en el adaptador se borra cuando el usuario se desplaza, lo que hace que la posición del titular del elemento cambie, la referencia perdida entre la lista y el elemento en la interfaz de usuario, el error ocurra en la próxima solicitud "notifyDataSetChanged" .

Reparar:

Revise su método de lista de actualizaciones. Si haces algo como

mainList.clear();
...
mainList.add() or mainList.addAll()
...
notifyDataSetChanged();

===> Error occur

Como arreglar. Cree un nuevo objeto de lista para el procesamiento del búfer y vuelva a asignarlo a la lista principal

List res = new ArrayList();
…..
res.add();  //add item or modify list
….
mainList = res;
notifyDataSetChanged();

Gracias a Nhan Cao por esta gran ayuda :)

Ramesh Pokharel
fuente
4

Mi problema desapareció después de modificar mi Adapterimplementación para usar una copia de la matriz de elementos en lugar de una referencia. Se setItems()llama al método cada vez que tenemos nuevos elementos para mostrar en el RecyclerView.

En vez de:

private class MyAdapter extends RecyclerView.Adapter<ItemHolder> {
     private List<MyItem> mItems;  

    (....)

    void setItems(List<MyItem> items) {
        mItems = items;
    }
}

Yo hice:

void setItems(List<MyItem> items) {
    mItems = new ArrayList<>(items);
}
Miguel A. Gabriel
fuente
Esto resolverá el problema, pero ¿no ocupará el doble de la memoria original?
Sreekanth Karumanaghat
@ MiguelA.Gabriel esto afectará el rendimiento? por ejemplo, en mi caso, estoy actualizando la matriz de recylerview con demasiada frecuencia, así que actualmente estoy haciendo esto suggestionsRecyclerView.swapAdapter(new CandidatesAdapter(mSuggestions), true); y este es mi constructor public CandidatesAdapter(List<String> suggestionsList) { this.suggestionsList = new ArrayList<>(suggestionsList); }
Mateen Chaudhry
@ mateen-chaudhry Probablemente lo hará. Deberá probarlo en su caso y decidir, o intentar usar otra de las soluciones propuestas. Como dije, es solo una solución y me funciona en mi caso.
Miguel A. Gabriel
3

Me he enfrentado a la misma situación. Y se resolvió agregando códigos antes de borrar su colección.

mRecyclerView.getRecycledViewPool().clear();

MagicDroidX
fuente
3

En mi caso, estaba actualizando los elementos y llamando notifyDataSetChangeden un hilo no UI. La mayoría de las veces funcionó, pero cuando ocurrieron muchos cambios rápidamente, colapsó. Cuando lo hice, en cambio, básicamente

activity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        changeData();
        notifyDataSetChanged();
    }
});

entonces dejó de estrellarse.

Erhannis
fuente
3

Solo necesita borrar su lista OnPostExecute()y no mientras lo hacePull to Refresh

// Setup refresh listener which triggers new data loading
        swipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {

                AsyncTask<String,Void,String> task = new get_listings();
                task.execute(); // clear listing inside onPostExecute

            }
        });

Descubrí que esto sucede cuando te desplazas durante una extracción para actualizar , ya que estaba borrando la lista antes del async task, lo que resultó en java.lang.IndexOutOfBoundsException: Inconsistency detected.

        swipeContainer.setRefreshing(false);
        //TODO : This is very crucial , You need to clear before populating new items 
        listings.clear();

De esa manera no terminarás con una inconsistencia

Fahad
fuente
2

También puede estar relacionado con la configuración del adaptador varias veces al mismo tiempo. Tenía un método de devolución de llamada que se activó 5-6 veces al mismo tiempo y estaba configurando el adaptador en esa devolución de llamada para que RecycledViewPool no pudiera manejar todos esos datos al mismo tiempo. Es una gran oportunidad, pero es mejor que lo revises de todos modos

Mustafa Güven
fuente
1
si mismo problema .. Pero solución? Usted da la razón solamente ... ¿Cómo arreglarlo?
Ranjith Kumar
@RanjithKumar, amablemente comparte tu forma de resolver el problema anterior Lo resolví usando mRecyclerView.getRecycledViewPool (). Clear (); antes de notificarDataSetChanged y usar el bloqueo sincronizado alrededor de la función de actualización del adaptador
Attiq ur Rehman
¿Puedes echar un vistazo a mi código? Creo que mi problema es como el tuyo. ¿Puedes ayudarme? stackoverflow.com/questions/50213362/…
Mateen Chaudhry
2

Utilizar

notifyDataSetChanged()

en lugar

notifyItemRangeInserted(0, YourArrayList.size())

en este caso.

Pankaj Talaviya
fuente
1
pero esto no es bueno para el rendimiento ¿verdad? notifyItemRangeInserted es mejor, el problema no radica aquí
Derekyy
2

Para solucionar este problema, solo llame a notifyDataSetChanged () con una lista vacía antes de actualizar la vista de reciclaje.

Por ejemplo

//Method for refresh recycle view

    if (!hcpArray.isEmpty())

hcpArray.clear (); // La lista para la vista de reciclaje de actualización

adapter.notifyDataSetChanged();
EKN
fuente
2
No es una solucion.
Miha_x64
@ Milha No obtuve ninguna otra solución para solucionar el problema del bloqueo. Pero la solución anterior me funcionó. Si no es una solución, dígame la solución adecuada.
EKN
Depende. Puede intentar usar DiffUtil, una herramienta de uso general para actualizar los contenidos de RecyclerView.
Miha_x64
2

En mi caso, acabo de eliminar la línea con setHasStableIds(true);

darkchaos
fuente
Pero HasStableIds (verdadero) mejora el rendimiento del Rv, ¿hay alguna solución alternativa?
Sreekanth Karumanaghat
En realidad, creo que podría deberse a diferentes razones, por lo que podría haber diferentes soluciones a este problema en función de cuál es la causa raíz.
Sreekanth Karumanaghat
2

En mi caso, estaba tratando de cambiar el contenido de mi adaptador en un subproceso de fondo, pero llamé a notify * en el subproceso principal / ui.

¡Eso no es posible! La razón por la que forzar la notificación al hilo principal es que la vista del reciclador quiere que edite su adaptador de respaldo en el hilo principal, incluso en la misma pila de llamadas.

Para resolver el problema, asegúrese de que cada operación a su adaptador, así como cada notificación ... ¡la llamada se realice en la interfaz de usuario / hilo principal !

Johannes Muenichsdorfer
fuente
2
agregar elementos a la lista en su adaptador debe hacerse en un hilo de fondo y llamar a notificar en postexecute. la adición de los datos en hilo de interfaz de usuario hace que la congelación de aplicación para algunos milisegundos o segundos si la adición de muchos datos
llorera diona
acordado con @dionellorera, debe quedar claro que un "cambio en el contenido del adaptador" significa específicamente modificar cualquier dato directamente, ya sean valores primitivos, propiedades de objetos u objetos en sí mismos
OzzyTheGiant
2

Me encontré con este desagradable rastro de pila con los nuevos componentes de arquitectura de Android recientemente. Esencialmente, tengo una lista de elementos en mi ViewModel que mi Fragmento observa, usando LiveData. Cuando ViewModel publica un nuevo valor para los datos, el Fragment actualiza el adaptador, pasa estos nuevos elementos de datos y notifica al adaptador que ha habido cambios.

Desafortunadamente, al pasar los nuevos elementos de datos al adaptador, no tuve en cuenta el hecho de que tanto el ViewModel como el Adaptador estarían apuntando a la misma referencia de objeto. Lo que significa que si actualizo los datos y llamo postValue()desde ViewModel, ¡hay una ventana muy pequeña donde los datos podrían actualizarse y el adaptador aún no ha sido notificado!

Mi solución fue crear una instancia de una copia nueva de los elementos cuando se pasa al adaptador:

mList = new ArrayList<>(passedList);

Con esta solución súper fácil, puede estar seguro de que los datos de su adaptador no cambiarán hasta justo antes de que se notifique a su adaptador.

Steve
fuente
2

Esta es la única solución que funcionó para mí, incluso probando muchas de las soluciones anteriores.

1.) Intilización

CustomAdapter scrollStockAdapter = new CustomAdapter(mActivity, new ArrayList<StockListModel>());
list.setAdapter(scrollStockAdapter);
scrollStockAdapter.updateList(stockListModels);

2.) Escribe este método en el adaptador

public void updateList(List<StockListModel> list) {
stockListModels.clear();
stockListModels.addAll(list);
notifyDataSetChanged();
}

stockListModels -> esta lista es la que está utilizando en el adaptador.

Ramkesh Yadav
fuente
2

Para mí, funcionó después de agregar esta línea de código:

mRecyclerView.setItemAnimator(null);
Fatih Gee
fuente
2
esto no es una solución en la mayoría de los casos, si desea animación, debe reescribir el código de su adaptador y encontrar sus errores al notificar los cambios
Dragos Rachieru
Funciona bien para mí. Estoy usando un adaptador real, así que no puedo controlar el flujo y habilité windowActivityTransitions en un estilo que causa este problema, gracias por salvarme el día.
Arul Mani
1

este problema puede ocurrir cuando intentas borrar tu lista, si vas a borrar tu lista de datos, especialmente cuando usas pull para actualizar, intenta usar un indicador booleano, inicialízalo como falso y dentro del método OnRefresh hazlo verdadero, borra tu lista de datos si el indicador es verdadero justo antes de agregarle los nuevos datos y luego hacerlo falso.

tu código podría ser así

 private boolean pullToRefreshFlag = false ;
 private ArrayList<your object> dataList ;
 private Adapter adapter ;

 public class myClass extend Fragment implements SwipeRefreshLayout.OnRefreshListener{

 private void requestUpdateList() {

     if (pullToRefresh) {
        dataList.clear
        pullToRefreshFlag = false;
     }

     dataList.addAll(your data);
     adapter.notifyDataSetChanged;


 @Override
 OnRefresh() {
 PullToRefreshFlag = true
 reqUpdateList() ; 
 }

}
Moaz H
fuente
1

Tuve un mismo problema anteriormente. Finalmente encontré una solución para eso

Lo que hago es notificar al adaptador que el elemento se ha eliminado y luego notificar que el rango del conjunto de datos del adaptador ha cambiado

 public void setData(List<Data> dataList) {
      if (this.dataList.size() > 0) {
          notifyItemRangeRemoved(0, dataList.size());
          this.dataList.clear();
      }
      this.dataList.addAll(dataList)
      notifyItemRangeChanged(0, dataList.size());

 }
Cheng
fuente
1

Me encontré con un problema similar y lo descubrí. Codifiqué algunos ejemplos para un caso de prueba, pero no me aseguré de que cada uno devolviera una identificación única y eso me causó el siguiente bloqueo. La solución de los ID resolvió el problema, ¡espero que esto ayude a alguien más!

DocBot
fuente
1

Una vez recibí el error también:

Causa: estaba tratando de actualizar una vista de reciclador desde una tarea asíncrona mientras intentaba simultáneamente obtener antiguos viewHolders borrados;

Código: Genero datos con solo presionar un botón, lógica de la siguiente manera

  1. Borrar los últimos elementos en la vista de reciclador
  2. Llame a la tarea asíncrona para generar datos
  3. OnPostExecute Actualiza la vista del Reciclador y NotifyDataSetChanged

Problema: cada vez que me desplazo rápido antes de generar mis datos, obtengo

Inconsistencia detectada. Adaptador de soporte de vista no válido positionViewHolder java.lang.IndexOutOfBoundsException: Inconsistencia detectada. Posición de elemento no válida 20 (desplazamiento: 2). Estado: 3

Solución: en lugar de borrar el RecyclerView antes de generar mis datos, lo dejo y luego lo Reemplace con los Nuevos Datos, el Call NotifyDatasetChanged, como se muestra a continuación;

       @Override
        protected void onPostExecute(List<Objects> o) {
            super.onPostExecute(o);
            recyclerViewAdapter.setList(o);
            mProgressBar.setVisibility(View.GONE);
            mRecyclerView.setVisibility(View.VISIBLE);
        }
EdgeDev
fuente
¿Puedes echarle un vistazo a mi código? Creo que mi problema es como el tuyo [enlace] ( stackoverflow.com/questions/50213362/… )
Mateen Chaudhry
1

Simplemente elimine todas las vistas de su Administrador de diseño antes de notificar. me gusta:

myLayoutmanager.removeAllViews();
BaBaX Ra
fuente
Funciona. Tuve problemas con la carga de desplazamiento y el cambio de pestaña.
Warwicky
1

Usar ListAdapter (androidx.recyclerview.widget.ListAdapter)llamada adapter.submitList(null)antes de llamar adapter.submitList(list):

adapter.submitList(null)
adapter.submitList(someDataList)
Sergey
fuente
1

Esta excepción se produjo en API 19, 21 (pero no nueva). En la rutina de Kotlin, cargué datos (en subproceso de fondo) y en el subproceso de interfaz de usuario agregué y les mostré:

adapter.addItem(item)

Adaptador:

var list: MutableList<Item> = mutableListOf()

init {
    this.setHasStableIds(true)
}

open fun addItem(item: Item) {
    list.add(item)
    notifyItemInserted(list.lastIndex)
}

Por alguna razón, Android no se procesa lo suficientemente rápido u otra cosa, por lo tanto, actualizo una lista en el postmétodo de RecyclerView(agregar, eliminar, actualizar eventos de elementos):

view.recycler_view.post { adapter.addItem(item) }

Esta excepción es similar a "No se puede llamar a este método en una devolución de llamada de desplazamiento. Las devoluciones de llamada de desplazamiento se pueden ejecutar durante un paso de medida y diseño en el que no se pueden cambiar los datos de RecyclerView. Cualquier llamada de método que pueda cambiar la estructura de RecyclerView o el contenido del adaptador se debe posponer para siguiente fotograma ": Recyclerview: no se puede llamar a este método en una devolución de llamada de desplazamiento .

CoolMind
fuente
0

Encontré esa configuración mRecycler.setLayoutFrozen (verdadero); en el método onRefresh del swipeContainer.

Resuelto el problema para mí.

swipeContainer.setOnRefreshListener(new   SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            orderlistRecycler.setLayoutFrozen(true);
            loadData(false);

        }
    });
Mark Sheekey
fuente
0

Este es un error bastante desagradable.

Para manejar el clic de mi artículo, utilicé una implementación RecyclerView.OnItemTouchListenersimilar a la solución encontrada en esta pregunta .

Después de muchas veces de actualizar la RecyclerViewfuente de datos y hacer clic en un elemento, esto IndexOutOfBoundsExceptionpodría bloquear mi aplicación. Cuando se hace clic en un elemento, RecyclerViewinternamente busca la vista subyacente correcta y le devuelve la posición. Al revisar el código fuente, vi que había algunos Tasksy los Threadsprogramé. Para abreviar la historia, básicamente es solo un estado ilegal donde dos fuentes de datos están entremezcladas y no sincronizadas y todo se vuelve loco.

En base a esto, eliminé mi implementación de RecyclerView.OnItemTouchListenery simplemente capturé el clic en el ViewHolderde Adaptermí mismo:

public void onBindViewHolder (final BaseContentView holder, final int position) {

    holder.itemView.setOnClickListener(new OnClickListener() {

      @Override
      public void onClick (View view) {

        // do whatever you like here
      }
    });

}

Puede que esta no sea la mejor solución, pero está libre de bloqueos por ahora. Espero que esto le ahorre algo de tiempo :).

DroidBender
fuente
La creación de un nuevo objeto cada vez que se llama a onBind dará como resultado una gran cantidad de objetos que serán recolectados de basura y el usuario podría experimentar congelamiento.
dephinera