Estou tentando atualizar os itens de uma revisão de reciclagem usando notifyDataSetChanged ().
Este é o meu método onBindViewHolder () no adaptador de reciclagem.
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
//checkbox view listener
viewHolder.getCheckbox().setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//update list items
notifyDataSetChanged();
}
});
}
O que eu quero fazer é atualizar os itens da lista, depois de marcar uma caixa de seleção. Eu recebo uma exceção ilegal:"Cannot call this method while RecyclerView is computing a layout or scrolling"
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
at android.support.v7.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:1462)
at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onChanged(RecyclerView.java:2982)
at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyChanged(RecyclerView.java:7493)
at android.support.v7.widget.RecyclerView$Adapter.notifyDataSetChanged(RecyclerView.java:4338)
at com.app.myapp.screens.RecycleAdapter.onRowSelect(RecycleAdapter.java:111)
Eu também usei notifyItemChanged (), mesma exceção. Alguma maneira secreta de atualizar para notificar o adaptador de que algo mudou?
android
android-recyclerview
Arthur
fonte
fonte
Respostas:
Você deve mover o método 'setOnCheckedChangeListener ()' para ViewHolder, que é a classe interna do seu adaptador.
onBindViewHolder()
não é um método que inicializeViewHolder
. Este método é a etapa de atualização de cada item do reciclador. Quando você ligarnotifyDataSetChanged()
,onBindViewHolder()
será chamado como o número de cada item vezes.Portanto, se você
notifyDataSetChanged()
inserironCheckChanged()
e inicializar checkBoxonBindViewHolder()
, receberá IllegalStateException por causa da chamada de método circular.clique na caixa de seleção -> onCheckedChanged () -> notifyDataSetChanged () -> onBindViewHolder () -> definir caixa de seleção -> onChecked ...
Simplesmente, você pode corrigir isso colocando um sinalizador no adaptador.
tente isso,
fonte
AdapterViewObserver
tempoonBindViewHolder()
em andamento.Você pode redefinir o ouvinte anterior antes de fazer alterações e não receberá essa exceção.
fonte
Usar um
Handler
para adicionar itens e chamar anotify...()
partir dissoHandler
corrigiu o problema para mim.fonte
Não sei bem, mas também tive o mesmo problema. Eu resolvi isso usando
onClickListner
emcheckbox
Tente isso, isso pode ajudar!
fonte
fonte
Quando você tem o erro de mensagem:
Simples, basta fazer o que causa a exceção em:
fonte
Encontrei uma solução simples -
Aqui, criamos um executável para notificarItemChanged para uma posição quando a recyclerview estiver pronta para lidar com isso.
fonte
seu item CheckBox está alterando o drawable quando você liga
notifyDataSetChanged();
para que essa exceção ocorra. Tente ligarnotifyDataSetChanged();
na postagem da sua visualização. Por exemplo:fonte
No começo, pensei que a resposta do Moonsoo (a resposta aceita) não funcionaria para mim porque não consigo inicializar o meu
setOnCheckedChangeListener()
no construtor ViewHolder porque preciso vinculá-lo toda vez para obter uma variável de posição atualizada. Mas levei muito tempo para perceber o que ele estava dizendo.Aqui está um exemplo da "chamada de método circular" sobre a qual ele está falando:
O único problema com isso é que, quando precisamos inicializar o comutador para ser ligado ou desligado (do estado salvo passado, por exemplo), ele está chamando o ouvinte que pode chamar
nofityItemRangeChanged
quais chamadasonBindViewHolder
novamente. Você não pode ligaronBindViewHolder
quando já estáonBindViewHolder
], porque não podenotifyItemRangeChanged
se já estiver no meio de notificar que o intervalo de itens foi alterado.Mas eu só precisava atualizar a interface do usuário para ativá-la ou desativá-la, sem querer realmente disparar nada.Aqui está a solução que aprendi com da resposta do JoniDS que impedirá o loop infinito. Desde que definamos o ouvinte como "nulo" antes de definir o Checked, ele atualizará a interface do usuário sem acionar o ouvinte, evitando o loop infinito. Então podemos definir o ouvinte depois.
Código do JoniDS:
Solução completa para o meu exemplo:
fonte
Por que não verificar o
RecyclerView.isComputingLayout()
estado da seguinte maneira?fonte
Enquanto o item está sendo vinculado pelo gerenciador de layout, é muito provável que você esteja configurando o estado marcado da sua caixa de seleção, o que está acionando o retorno de chamada.
Obviamente, isso é um palpite, porque você não publicou o rastreamento de pilha completa.
Você não pode alterar o conteúdo do adaptador enquanto o RV está recalculando o layout. Você pode evitá-lo não chamando notifyDataSetChanged se o estado verificado do item for igual ao valor enviado no retorno de chamada (que será o caso se a chamada
checkbox.setChecked
estiver acionando o retorno de chamada).fonte
Use onClickListner na caixa de seleção em vez de OnCheckedChangeListener, resolverá o problema
fonte
Antes de
notifyDataSetChanged()
verificar isso com este método:recyclerView.IsComputingLayout()
fonte
Post simples de uso:
fonte
Corri para este problema exato! Depois que a resposta de Moonsoo realmente não flutuou no meu barco, eu errei um pouco e encontrei uma solução que funcionou para mim.
Primeiro, aqui está um pouco do meu código:
Você notará que estou notificando especificamente o adaptador para a posição que estou mudando, em vez de todo o conjunto de dados como você está fazendo. Dito isto, embora eu não possa garantir que isso funcione para você, resolvi o problema envolvendo meu
notifyItemChanged()
chamada em um bloco de tentativa / captura. Isso simplesmente capturou a exceção, mas ainda permitiu que meu adaptador registrasse a alteração de estado e atualizasse a exibição!Espero que isso ajude alguém!
EDIT: admito que provavelmente essa não é a maneira correta / madura de lidar com o problema, mas como ele não parece estar causando problemas ao deixar a exceção sem tratamento, pensei em compartilhar caso fosse bom o suficiente para outra pessoa.
fonte
Isso está acontecendo porque você provavelmente está configurando o 'ouvinte' antes de configurar o valor dessa linha, o que faz com que o ouvinte seja acionado quando você 'configura o valor' para a caixa de seleção.
O que você precisa fazer é:
fonte
fonte
basta usar o
isPressed()
método deCompoundButton
poronCheckedChanged(CompoundButton compoundButton, boolean isChecked)
exemplo
fonte
Eu tive o mesmo problema ao usar a caixa de seleção e o RadioButton. Substituindo
notifyDataSetChanged()
pornotifyItemChanged(position)
trabalhado. Eu adicionei um campo booleanoisChecked
ao modelo de dados. Atualizei o valor booleano eonCheckedChangedListener
, em , ligueinotifyItemChanged(adapterPosition)
. Esta pode não ser a melhor maneira, mas funcionou para mim. O valor booleano é usado para verificar se o item está marcado.fonte
na maioria das vezes isso acontece porque a notificação é alterada chamando o evento de verificação da caixa de seleção e, nesse caso, novamente , a notificação é alterada .
Para resolvê-lo, basta marcar se a caixa de seleção está marcada programaticamente ou pressionada pelo usuário. existe o método isPressed para isso.
então envolva todo o código do listner dentro do método isPressed. e está feito.
fonte
Sofri com esse problema por hora e é assim que você pode corrigi-lo. Mas antes de começar, existem algumas condições para esta solução.
CLASSE MODELO
Caixa de seleção na classe ADAPTER
CONSTRUTOR DE CLASSE ADAPTADOR E LISTA DE MODELOS
ONBINDVIEW [Use onclick no lugar de onCheckChange]
}
fonte
Para mim, ocorreu um problema ao sair do EditText por Concluído, Voltar ou toque de entrada externo. Isso faz com que o modelo seja atualizado com o texto inserido e, em seguida, atualize a exibição do reciclador por meio da observação de dados ao vivo.
O problema era que o cursor / foco permanecia no EditText.
Quando eu apaguei o foco usando:
O método de notificação de alteração de dados da exibição do reciclador parou de gerar esse erro.
Penso que esta é uma das possíveis razões / soluções para este problema. É possível que essa exceção possa ser corrigida de outra maneira, pois pode ser causada por uma razão totalmente diferente.
fonte