RecyclerView: Inconsistência detectada. Posição do item inválida

271

Nosso controle de qualidade detectou um erro: ao girar o dispositivo Android (Droid Turbo), ocorreu o seguinte acidente relacionado ao RecyclerView :

java.lang.IndexOutOfBoundsException: Inconsistência detectada. Posição 2 do item inválida (deslocamento: 2) .state: 3

Para mim, parece um erro interno no RecyclerView, pois não consigo pensar em nenhuma maneira de isso ser causado diretamente pelo nosso código ...

Alguém já encontrou este problema?

Qual seria a solução?

Uma solução brutal pode ser a captura da exceção quando isso acontece e recriar a instância do RecyclverView do zero, para evitar ficar com um estado corrompido.

Mas, se possível, eu gostaria de entender melhor o problema (e talvez corrigi-lo na fonte), em vez de mascará-lo.

O bug não é fácil de reproduzir, mas é fatal quando acontece.

O rastreamento de pilha completo:

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
fonte
2
Uma pergunta: Qual é a consistência da sua reprodução? Eu sei que isso é um erro no código do google aqui e aqui . Mas isso pode ser evitado. Então, isso está acontecendo a cada rotação?
VicVu
Oi. Isso acontece apenas raramente, mas quando acontece, é fatal para o aplicativo.
KarolDepka
Obrigado pelos links para os erros. O primeiro parece mais relevante que o segundo.
KarolDepka
1
Sim, acho que sua melhor aposta é não permitir alterações na exibição da lista durante a rotação.
VicVu
1
Se você pudesse se reproduzir facilmente, sugiro imprimir o valor de 'getItemCount' antes de todas as chamadas para 'notify *' ... você pode descobrir que a contagem de itens não corresponde às suas suposições.
Rich Ehmer

Respostas:

209

Eu tive um problema (possivelmente) relacionado - inserir uma nova instância de uma atividade com um RecyclerView, mas com um adaptador menor, estava causando esse travamento para mim.

RecyclerView.dispatchLayout()pode tentar retirar itens do refugo antes de ligar mRecycler.clearOldPositions(). A conseqüência é que ele estava puxando itens do pool comum que tinham posições maiores que o tamanho do adaptador.

Felizmente, ele só faz isso se PredictiveAnimationsestiver ativado, então minha solução foi subclassar GridLayoutManager( LinearLayoutManagertem o mesmo problema e 'consertar') e substituir supportsPredictiveItemAnimations()para retornar false:

/**
 * 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
fonte
4
Isso funcionou para mim, e desativar as animações preditivas não faz com que você perca as animações todos juntos. Bravo.
Robert Liberatore
8
Muito obrigado senhor! Trabalhei instantaneamente com o LinearLayoutManager, provavelmente me poupando dias.
levavare
8
Muito obrigado. Esta solução é trabalhada com LinearLayoutManager.
Pruthviraj
8
Eu acho que esse cara merece que construamos uma estátua em homenagem a sua preciosa ajuda ... É uma das piores questões documentadas na web, mas parece que muitos desenvolvedores encontram essa questão ... Eu me pergunto como você achou que isso poderia acontecer. será ignorado se PredictiveAnimations for false, @KasHunt? Porque, o stacktrace é muito obscuro ...
PAD
4
Alguém sabe, como consertar isso sem esse hack? Porque notifyDatasetChanged foi retirado a favor de DiffUtil
Anton Shkurenko 21/03
83

No meu caso (excluir / inserir dados na minha estrutura de dados), eu precisava limpar o pool de reciclagem e notificar o conjunto de dados alterado!

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

MatejC
fonte
6
Normalmente não digo isso, mas muito obrigado. Eu tentei TUDO para consertar essa falha que ocorre esporadicamente quando estou movendo vários itens da lista em ordem rápida. Passei literalmente uma semana inteira tentando resolver esse problema. Eu me afastei dele por alguns meses para tentar dar ao meu cérebro a chance de abordá-lo de maneira diferente, e depois encontrei isso na minha primeira tentativa no Google. Saúde!
Chantell Osejo
Deixe-me pegar uma tonelada de cookies, porque você merece cada um deles. Obrigado.
antonis_st
por que você tem que fazer isso?
dabluck
9
Essa é uma operação bastante pesada que derruba o objetivo de reciclar visualizações.
gjsalot
@gjsalot Então, se eu usar isso, ele pode causar alguns problemas?
Sreekanth Karumanaghat
38

Use em notifyDataSetChanged()vez disso notifyItem...neste caso.

Khaintt
fonte
5
Em alguns casos, este é o caminho a percorrer. Tive uma situação em que substituí todos os meus itens, mas não estava sendo sincero com o adaptador, apenas dizendo que havia inserido alguns novos itens (notifyItemRangeInserted), sem antes dizer que também havia removido itens. O adaptador esperava que houvesse mais itens do que realmente havia. Se o uso de qualquer um dos métodos de notificação do adaptador esperar notifyDataSetChanged, como notifyItemRangeRemoved / Inserted / Updated, o chamador terá total responsabilidade de informar ao adaptador exatamente o que foi alterado ou você poderá acabar com esse "estado inconsistente".
JHH
19
Esta não é uma solução.
21717 Mih_x64
Este não é o caminho a percorrer. Se isso funcionar, significa que você acabou de alterar o intervalo notifyItem...e a correção, que começará a funcionar em vez de renderizar novamente todos os itens.
Ranjan 12/07
12

Resolvi isso atrasando o mRecycler.setAdapter(itemsAdapter)caixa depois de adicionar todos os itens ao adaptador mRecycler.addAll(items)e ele funcionou. Não faço ideia por que fiz isso, foi a partir do código de uma biblioteca que olhei e vi essas linhas na "ordem errada". Tenho certeza de que é isso, por favor, se alguém puder confirmar, explique por que é tão? Não tenho certeza se esta é uma resposta válida, mesmo

Odaym
fonte
Eu acho que esta é a solução, uma vez que adiei o adaptador, tudo bem, acredito ... agora ele aparece quando o adaptador é definido no thread da interface do usuário e a adição de itens a ele.
EngineSense
18
Eu usei em swapAdapter(adapter, true)vez de setAdapter(adapter)e ajudou.
frangulyan
11

Eu tive um problema semelhante, mas não exatamente o mesmo. No meu caso, em um ponto, eu estava limpando a matriz que foi passada para a revisão de reciclagem

mObjects.clear();

e não chamando notifyDataSetChanged, pois eu não queria que a recyclerview limpe imediatamente as visualizações. Eu estava preenchendo novamente a matriz mObjects no AsyncTask.

Aalap
fonte
9

Eu tive o mesmo problema com o recyclerView. Acabei de notificar o adaptador sobre a alteração do conjunto de dados logo após a limpeza da lista.

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

mList.addAll(newData);
mAdapter.notifyDataSetChanged();
Reza
fonte
1
Este simples erro me fez perder muito tempo, muito obrigado!
leb1755
7

Eu tenho o mesmo problema. Ocorreu quando eu estava rolando rapidamente e chamando a API e atualizando dados. Depois de tentar todas as coisas para evitar falhas, encontrei a solução.

mRecyclerView.stopScroll();

Vai funcionar.

Anand Savjani
fonte
Esta é uma solução alternativa, não uma correção. Você está forçando-o a parar o pergaminho. Bad UX
Dr. anDRO
1
@ Dr.aNdRO: O adaptador precisa definir a posição e, se você continuar rolando a recylerview, o adaptador não poderá definir os dados que são a causa da falha. UX não é ruim
Anand Savjani
1
faz sentido. Parar a rolagem não é ruim, pois a atualização de dados está acontecendo.
Sush
6

Estou alterando os dados para o RecyclerViewsegundo plano Thread. Eu tenho o mesmo Exceptionque o OP. Eu adicionei isso depois de alterar os dados:

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

Espero que ajude

kashyap jimuliya
fonte
valeu cara! essa é a única resposta que faz sentido do ponto de vista do desenvolvimento do Android.
user347187 14/01
Enquanto eu também resolvi com a ajuda de view.recycler_view.post, eu usei notifyItemInserted. No meu caso, já foi thread da interface do usuário.
CoolMind 26/02
6

Este erro ocorre quando a lista no adaptador é limpa quando a rolagem do usuário faz com que a posição do suporte do item seja alterada, refs perdida entre a lista e o item na interface do usuário, o erro ocorra no próximo "notifyDataSetChanged" solicitação .

Consertar:

Revise seu método da lista de atualizações. Se você fizer algo como

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

===> Error occur

Como consertar. Crie um novo objeto de lista para processamento de buffer e atribua novamente à lista principal depois disso.

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

Obrigado a Nhan Cao por esta grande ajuda :)

Ramesh Pokharel
fonte
4

Meu problema desapareceu depois que modifiquei minha Adapterimplementação para usar uma cópia da matriz de itens em vez de uma referência. O setItems()método é chamado cada vez que temos novos itens para mostrar no RecyclerView.

Ao invés de:

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

    (....)

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

Eu fiz:

void setItems(List<MyItem> items) {
    mItems = new ArrayList<>(items);
}
Miguel A. Gabriel
fonte
Isso resolverá o problema, mas ele não ocupará o dobro da memória original?
Sreekanth Karumanaghat
@ MiguelA.Gabriel isso afetará o desempenho? por exemplo no meu caso eu estou atualizando variedade de recylerview com muita freqüência por isso neste momento estou fazendo isso suggestionsRecyclerView.swapAdapter(new CandidatesAdapter(mSuggestions), true); e este é meu construtor public CandidatesAdapter(List<String> suggestionsList) { this.suggestionsList = new ArrayList<>(suggestionsList); }
Mateen Chaudhry
@ mateen-chaudhry Provavelmente será. Você precisará testá-lo no seu caso e decidir ou tentar usar outra das soluções propostas. Como eu disse, é apenas uma solução alternativa e funciona para mim no meu caso.
Miguel A. Gabriel
3

Eu já enfrentei a mesma situação. E foi resolvido adicionando códigos antes de limpar sua coleção.

mRecyclerView.getRecycledViewPool().clear();

MagicDroidX
fonte
3

No meu caso, eu estava atualizando os itens e chamando notifyDataSetChangedum thread que não era da interface do usuário. Na maioria das vezes funcionava, mas quando muitas mudanças aconteciam rapidamente, elas travavam. Quando eu fiz, basicamente

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

então parou de bater.

Erhannis
fonte
3

Você só precisa limpar sua lista OnPostExecute()e não enquanto estiverPull 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

            }
        });

Descobri que isso acontece quando você rola durante um pull para atualizar , pois eu estava limpando a lista antes de async task, resultando em java.lang.IndexOutOfBoundsException: Inconsistency detected.

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

Dessa forma, você não terminará com uma inconsistência

Fahad
fonte
2

Também pode estar relacionado à configuração do adaptador várias vezes ao mesmo tempo. Eu tinha um método de retorno de chamada que foi acionado 5 a 6 vezes ao mesmo tempo e estava configurando o adaptador nesse retorno de chamada para que o RecycledViewPool não pudesse lidar com todos esses dados de maneira contemporânea. É uma grande chance, mas é melhor você conferir de qualquer maneira.

Mustafa Güven
fonte
1
sim mesmo problema .. Mas solução? Você dá apenas o motivo .. Como consertar?
Ranjith Kumar
@RanjithKumar, compartilhe seu caminho para resolver o problema acima. Eu o resolvi usando mRecyclerView.getRecycledViewPool (). Clear (); antes notifyDataSetChanged e usando bloco sincronizado em torno função de actualização de adaptador
Attiq ur Rehman
você pode por favor dê uma olhada no meu código eu acho que o meu problema é como o seu, você pode me ajudar a stackoverflow.com/questions/50213362/...
Mateen Chaudhry
2

Usar

notifyDataSetChanged()

em vez de

notifyItemRangeInserted(0, YourArrayList.size())

nesse caso.

Pankaj Talaviya
fonte
1
mas isso não é bom para o desempenho, certo? notifyItemRangeInserted é melhor, o problema não está aqui
Derekyy
2

Para corrigir esse problema, chame notifyDataSetChanged () com lista vazia antes de atualizar a exibição de reciclagem.

Por exemplo

//Method for refresh recycle view

    if (!hcpArray.isEmpty())

hcpArray.clear (); // A lista para exibição de reciclagem de atualização

adapter.notifyDataSetChanged();
EKN
fonte
2
Não é uma solução.
22817 Mih_x64
@Milha Não recebi nenhuma outra solução para corrigir o problema de travamento. Mas a solução acima é trabalhada para mim. Se não for uma solução, diga-me a solução adequada.
EKN
Depende. Você pode tentar usar o DiffUtil - uma ferramenta de uso geral para atualizar o conteúdo do RecyclerView.
precisa saber é o seguinte
2

No meu caso, acabei de remover a linha com setHasStableIds(true);

darkchaos
fonte
Mas HasStableIds (true) melhora o desempenho do Rv, existe alguma solução alternativa?
Sreekanth Karumanaghat 20/0318
Na verdade, acho que isso pode ser devido a diferentes razões, portanto, pode haver soluções diferentes para esse problema com base na causa raiz.
Sreekanth Karumanaghat
2

No meu caso, eu estava tentando alterar o conteúdo do meu adaptador em um thread em segundo plano, mas chamei notify * no thread principal / interface do usuário.

Isso não é possível! O motivo pelo qual a notificação é forçada ao encadeamento principal é que a reciclagem deseja que você edite seu adaptador de suporte no encadeamento principal, mesmo na mesma pilha de chamadas.

Para resolver o problema, verifique se todas as operações no adaptador e todas as notificações ... são feitas no thread da interface do usuário / principal !

Johannes Muenichsdorfer
fonte
2
a adição de itens à lista em seu adaptador deve ser feita em um encadeamento em segundo plano e chame notificar em pós-execução. adição de dados no segmento interface do usuário torna o congelamento app para alguns milissegundos ou segundos, se a adição de muitos dados
llorera diona
concordou com @dionellorera, deve ficar claro que uma "mudança no conteúdo do adaptador" significa especificamente a modificação quaisquer dados directamente, se os valores primitivos, propriedades de objectos, ou os próprios objetos
OzzyTheGiant
2

Encontrei esse rastreio de pilha desagradável com os novos componentes da arquitetura do Android recentemente. Essencialmente, tenho uma lista de itens no meu ViewModel que são observados pelo meu fragmento, usando o LiveData. Quando o ViewModel publica um novo valor para os dados, o Fragmento atualiza o adaptador, passando esses novos elementos de dados e notificando o adaptador de que houve alterações.

Infelizmente, ao passar os novos elementos de dados para o adaptador, não considerei o fato de que o ViewModel e o Adapter estivessem apontando para a mesma referência de objeto! Ou seja, se eu atualizar os dados e ligarpostValue() de dentro do ViewModel, há uma janela muito pequena onde os dados podem ser atualizados e o adaptador ainda não foi notificado!

Minha correção foi instanciar uma cópia nova dos elementos quando passados ​​para o adaptador:

mList = new ArrayList<>(passedList);

Com essa correção super fácil, você pode garantir que os dados do adaptador não serão alterados até pouco antes de o adaptador ser notificado.

Steve
fonte
2

Esta é a única solução que funcionou para mim, mesmo tentando muitas das soluções acima.

1.) fertilização

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

2.) Escreva este método no adaptador

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

stockListModels -> esta lista é a que você está usando no adaptador.

Ramkesh Yadav
fonte
2

Para mim, funcionou depois de adicionar esta linha de código:

mRecyclerView.setItemAnimator(null);
Fatih Gee
fonte
2
esta não é uma solução na maioria dos casos, se você quiser animação que você tem te reescrever seu código adaptador e encontrar seus erros em mudanças notificantes
Dragos Rachieru
Estou usando o adaptador real para não poder controlar o fluxo e ativei o windowActivityTransitions em um estilo que causa esse problema graças a você, salve o meu dia.
Arul Mani
1

esse problema pode ocorrer quando você tenta limpar sua lista, se você estiver limpando sua lista de dados, especialmente quando estiver usando pull para atualizar, tente usar um sinalizador booleano, inicialize-o como false e, se o método OnRefresh for verdadeiro, limpe seu dataList se o flag for verdadeiro imediatamente antes de adicionar os novos dados a ele e depois torná-lo falso.

seu código pode ser assim

 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
fonte
1

Eu tive um mesmo problema anteriormente. Finalmente encontrei uma solução alternativa para isso

O que faço é notificar o adaptador que o item foi removido e notificar o intervalo do conjunto de dados do adaptador alterado

 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
fonte
1

Corri para um problema semelhante e só descobri. Codifiquei alguns exemplos para um caso de teste, mas não garanti que cada um retornasse um ID exclusivo e que causasse a falha abaixo para mim. A correção dos IDs resolveu o problema. Espero que isso ajude outra pessoa!

DocBot
fonte
1

uma vez eu também recebi o erro:

Causa: Eu estava tentando atualizar uma Exibição do Reciclador de uma tarefa assíncrona enquanto tentava obter antigos viewHolders excluídos;

Código: eu gero dados com o pressionar de um botão, lógica da seguinte maneira

  1. Limpe os últimos itens na exibição do reciclador
  2. Chamar tarefa assíncrona para gerar dados
  3. OnPostExecute Atualize a exibição Recycler e NotifyDataSetChanged

Problema: sempre que eu rolar rapidamente antes de gerar meus dados, recebo

Inconsistência detectada. Adaptador de suporte de exibição inválido positionViewHolder java.lang.IndexOutOfBoundsException: Inconsistência detectada. Posição 20 do item inválida (deslocamento: 2) .state: 3

Solução: em vez de limpar o RecyclerView antes de gerar meus dados, eu o deixo e o substituo pelos Novos dados, a chamada NotifyDatasetChanged, como mostrado abaixo;

       @Override
        protected void onPostExecute(List<Objects> o) {
            super.onPostExecute(o);
            recyclerViewAdapter.setList(o);
            mProgressBar.setVisibility(View.GONE);
            mRecyclerView.setVisibility(View.VISIBLE);
        }
EdgeDev
fonte
você pode por favor dê uma olhada no meu código eu acho que o meu problema é como o seu [link] ( stackoverflow.com/questions/50213362/... )
Mateen Chaudhry
1

Basta remover todas as visualizações do seu Gerenciador de layout antes de notificar. gostar:

myLayoutmanager.removeAllViews();
BaBaX Ra
fonte
Funciona. Eu tive um problema com a carga de rolagem e a alteração da guia.
Warwicky 29/03/19
1

Usando a ListAdapter (androidx.recyclerview.widget.ListAdapter)chamada adapter.submitList(null)antes de ligar adapter.submitList(list):

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

Essa exceção foi gerada na API 19, 21 (mas não nova). Na corotina Kotlin, carreguei dados (no thread de segundo plano) e no thread da interface do usuário adicionei e mostrei a eles:

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 algum motivo, o Android não é renderizado rápido o suficiente ou qualquer outra coisa, então eu atualizo uma lista no postmétodo do RecyclerView(adicionar, remover, atualizar eventos dos itens):

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

Essa exceção é semelhante a "Não é possível chamar esse método em um retorno de chamada de rolagem. Os retornos de chamada de rolagem podem ser executados durante uma passagem de medida e layout em que você não pode alterar os dados do RecyclerView. Qualquer chamada de método que possa alterar a estrutura do RecyclerView ou o conteúdo do adaptador deve ser adiada próximo quadro. ": Reciclerview - não é possível chamar esse método em um retorno de chamada de rolagem .

CoolMind
fonte
0

Eu achei que a configuração mRecycler.setLayoutFrozen (true); no método onRefresh do swipeContainer.

resolveu o problema para mim.

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

        }
    });
Mark Sheekey
fonte
0

Este é um bug bastante desagradável.

Para lidar com o clique do item, usei uma implementação RecyclerView.OnItemTouchListenersemelhante à solução encontrada nesta pergunta .

Depois de muitas vezes atualizando a RecyclerViewfonte de dados e clicando em um item, isso IndexOutOfBoundsExceptiontravaria meu aplicativo. Quando um item é clicado, o RecyclerViewinterna procura a visão subjacente correta e devolve sua posição. Verificando o código fonte, vi que havia alguns TaskseThreads agendados. Para resumir a história, basicamente é apenas um estado ilegal em que duas fontes de dados são misturadas e não sincronizadas e a coisa toda fica louca.

Com base nisso, eu removi minha implementação do RecyclerView.OnItemTouchListenere simplesmente pegou o clique sobre o ViewHolderdo Adaptermim mesmo:

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

}

Esta pode não ser a melhor solução, mas está livre de falhas por enquanto. Espero que isso poupe algum tempo :).

DroidBender
fonte
Criar um novo objeto sempre que o onBind for chamado resultará em muitos objetos que serão coletados como lixo e o usuário poderá congelar.
dephinera