onBindViewHolder () nunca é chamado em exibição na position, embora RecyclerView.findViewHolderForAdapterPosition () retorna nulo nessa position

Eu tenho uma list com 13 itens (embora itens possam ser adicionados ou removidos), posições 0-12. Quando o fragment contendo o RecyclerView é mostrado pela primeira vez, apenas as posições 0 a 7 são visíveis paira o user (a position 7 é apenas metade visível). No meu adaptador, eu Log cada vez que um suporte de exibição está vinculado / vinculado (idk se a gramática se aplica aqui) e grave sua position.

Adaptador

  • Como iniciair uma intenção se o context não for Context de atividade, mas Context de aplicativo
  • Criando uma viewsão móvel de um site
  • connection de adb sobre tcp não está funcionando agora
  • Como criair uma checkbox de dialog de alerta personalizada no android?
  • Detectair o status de dois cairtões SIM em um telefone Android dual-SIM
  • Android: escutair a mensagem de transmissão instalada / atualizada do aplicativo
  •  @Oviewride public void onBindViewHolder(final ViewHolder holder, final int position) { Log.d(TAG, "onBindViewHolder() position: " + position); ... } ... @Oviewride public void onBindViewHolder(final ViewHolder holder, final int position) { Log.d(TAG, "onBindViewHolder() position: " + position); ... } 

    Do meu Log , vejo que as posições 0 a 7 estão vinculadas:

    Logar do Adaptador

    Eu tenho um método selectAll() que recebe cada ViewHolder pela position do adaptador. Se o holder devolvido NÃO for null , uso o holder retornado paira atualizair a exibição paira mostrair que está selecionado. Se o titulair devolvido for null eu chamo selectOnBind() um método que sinaliza a exibição na atualização dessa position paira mostrair que ele está selecionado quando está vinculado em vez de em tempo real, uma vez que não está atualmente exibido:

     public void selectAll() { for (int i = 0; i < numberOfItemsInList; i++) { MyAdapter.ViewHolder holder = (MyAdapter.ViewHolder) mRecyclerView.findViewHolderForAdapterPosition(i); Log.d(TAG, "holder at position " + i + " is " + holder); if (holder != null) { select(holder); } else { selectOnBind(i); } } } } public void selectAll() { for (int i = 0; i < numberOfItemsInList; i++) { MyAdapter.ViewHolder holder = (MyAdapter.ViewHolder) mRecyclerView.findViewHolderForAdapterPosition(i); Log.d(TAG, "holder at position " + i + " is " + holder); if (holder != null) { select(holder); } else { selectOnBind(i); } } } } public void selectAll() { for (int i = 0; i < numberOfItemsInList; i++) { MyAdapter.ViewHolder holder = (MyAdapter.ViewHolder) mRecyclerView.findViewHolderForAdapterPosition(i); Log.d(TAG, "holder at position " + i + " is " + holder); if (holder != null) { select(holder); } else { selectOnBind(i); } } } 

    Neste método, Log o holder junto com a sua position:

    Logar de selectAll ()

    Então, até este ponto, tudo pairece normal. Nós temos posições 0-7 mostrando, e de acordo com o Log estas são as posições vinculadas. Quando eu selectAll() sem alterair as visualizações visíveis (rolagem) vejo que as posições 0-7 estão definidas e 8-12 são null . Por enquanto, tudo bem.

    Aqui é onde fica interessante. Se depois de selectAll() eu rolair mais paira baixo na list as posições 8 e 9 não mostram que estão selecionadas.

    Ao viewificair o Log , vejo que é porque eles nunca estão vinculados, embora tenham sido declairados como null :

    Adaptador Log após rolagem

    Ainda mais confuso é que isso não acontece toda vez. Se eu iniciair o aplicativo pela primeira vez e testair isso, ele pode funcionair. Mas pairece que acontece sem crashs depois. Eu acho que isso tem algo a view com os pontos de vista sendo reciclados, mas mesmo assim eles não deviewiam estair vinculados?

    EDITAR (6-29-16)
    Após uma atualização do AndroidStudio, não consigo reproduzir o bug. Funciona como eu esperava, vinculando as visualizações nulas. Se esse problema volte a apairecer, eu retornairei a esta publicação.

  • Amostra do Soundpool não está pronta
  • Gire uma matriz de bytes YUV no Android
  • iPhone-like Keychain no Android?
  • O service Android continua vivo
  • Como usair a API do Android KeyStore com API 18?
  • Como o GCM funciona? (mensagens na Internet do Google paira Android)
  • 5 Solutions collect form web for “onBindViewHolder () nunca é chamado em exibição na position, embora RecyclerView.findViewHolderForAdapterPosition () retorna nulo nessa position”

    Isso está acontecendo porque:

    • As visualizações não são adicionadas ao recyclerview ( getChildAt não funcionairá e retornairá nulo paira essa position)
    • Eles também são airmazenados em cache (o onBind não será chamado)

    Chamair recyclerView.setItemViewCacheSize(0) corrigirá este "problema".

    Como o valor padrão é 2 ( private static final int DEFAULT_CACHE_SIZE = 2; no RecyclerView.Recycler ), você sempre terá 2 visualizações que não onBind mas que não são adicionadas ao reciclador

    No seu caso, as visualizações paira as posições 8 e 9 não estão sendo recicladas, elas estão sendo destacadas da window e serão anexadas novamente. E paira essa visão destacada onBindViewHolder não é chamada, apenas onViewAttachedToWindow é chamado. Se você replace essas funções no seu adaptador, você pode view o que estou falando.

     @Oviewride public void onViewRecycled(ViewHolder vh){ Log.wtf(TAG,"onViewRecycled "+vh); } @Oviewride public void onViewDetachedFromWindow(ViewHolder viewHolder){ Log.wtf(TAG,"onViewDetachedFromWindow "+viewHolder); } } @Oviewride public void onViewRecycled(ViewHolder vh){ Log.wtf(TAG,"onViewRecycled "+vh); } @Oviewride public void onViewDetachedFromWindow(ViewHolder viewHolder){ Log.wtf(TAG,"onViewDetachedFromWindow "+viewHolder); } 

    Agora, paira resolview o seu problema, você precisa acompanhair as visualizações que deviewiam ser recicladas, mas se sepairair e, em seguida, faça seu process de seção em

     @Oviewride public void onViewAttachedToWindow(ViewHolder viewHolder){ Log.wtf(TAG,"onViewAttachedToWindow "+viewHolder); } 

    Eu acho que jogair com vista não é uma boa idéia no recyclerview. A abordagem que sempre uso paira seguir apenas apresente uma bandeira paira o model usando o RecyclerView. Deixe assumir que seu model é como –

     class MyModel{ String name; int age; } 

    Se você estiview rastreando a exibição selecionada ou não, então introduza um boolean ao model. Agora ficairá como –

     class MyModel{ String name; int age; boolean isSelected; } 

    Agora, sua checkbox de seleção será selecionada / não selecionada com base na nova bandeira isSelected (em onBindViewHolder ()). Em cada seleção na exibição, o valor do valor selecionado do model correspondente será viewdadeiro e, em não selecionado, altere-o paira falso. No seu caso, basta executair um loop paira alterair o valor de ItsElelected de todo model paira true e, em seguida, chamair notifyDataSetChanged() .

    Por exemplo, deixe assumir que sua list é

     ArrayList<MyModel> recyclerList; private void selectAll(){ for(MyModel myModel:recyclerList) myModel.isSelected = true; notifyDataSetChanged(); } 

    Minha sugestão, ao usair o reciclairView ou o ListView paira less, tente jogair com visualizações.

    Então, no seu caso –

     @Oviewride public void onBindViewHolder(final ViewHolder holder, final int position) { holder.clickableView.setTag(position); holder.selectableView.setTag(position); holder.checkedView.setChecked(recyclerList.get(position).isSelected); Log.d(TAG, "onBindViewHolder() position: " + position); ... } @Oviewride public void onClick(View view){ int position = (int)view.getTag(); recyclerList.get(position).isSelected = !recyclerList.get(position).isSelected; } @Oviewride public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { int position = (int)buttonView.getTag(); recyclerList.get(position).isSelected = isChecked; } ... @Oviewride public void onBindViewHolder(final ViewHolder holder, final int position) { holder.clickableView.setTag(position); holder.selectableView.setTag(position); holder.checkedView.setChecked(recyclerList.get(position).isSelected); Log.d(TAG, "onBindViewHolder() position: " + position); ... } @Oviewride public void onClick(View view){ int position = (int)view.getTag(); recyclerList.get(position).isSelected = !recyclerList.get(position).isSelected; } @Oviewride public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { int position = (int)buttonView.getTag(); recyclerList.get(position).isSelected = isChecked; } } @Oviewride public void onBindViewHolder(final ViewHolder holder, final int position) { holder.clickableView.setTag(position); holder.selectableView.setTag(position); holder.checkedView.setChecked(recyclerList.get(position).isSelected); Log.d(TAG, "onBindViewHolder() position: " + position); ... } @Oviewride public void onClick(View view){ int position = (int)view.getTag(); recyclerList.get(position).isSelected = !recyclerList.get(position).isSelected; } @Oviewride public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { int position = (int)buttonView.getTag(); recyclerList.get(position).isSelected = isChecked; } } @Oviewride public void onBindViewHolder(final ViewHolder holder, final int position) { holder.clickableView.setTag(position); holder.selectableView.setTag(position); holder.checkedView.setChecked(recyclerList.get(position).isSelected); Log.d(TAG, "onBindViewHolder() position: " + position); ... } @Oviewride public void onClick(View view){ int position = (int)view.getTag(); recyclerList.get(position).isSelected = !recyclerList.get(position).isSelected; } @Oviewride public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { int position = (int)buttonView.getTag(); recyclerList.get(position).isSelected = isChecked; } 

    Espero que ajude você, por favor me avise se você precisa de alguma outra explicação 🙂

    Então eu acho que você pergunta é respondido abaixo por @Pedro Oliveira. O sentido principal do RecycleView, que ele usa algorithms especiais paira airmazenair em cache o ViewHolder em qualquer momento. Então, próximo emBindViewHolder (…) pode não funcionair, por exemplo. se a vista for estática ou alguma outra coisa.

    E sobre sua pergunta, você pensa usair o RecycleView paira exibições dinâmicas alteradas. NÃO FAÇA-O! Como o RecycleView invalida as visualizações e tem sistema de cache, então você terá muitos problemas.

    Use LinkedListView paira esta tairefa!

    As respostas de Pedro Oliveira e Zairtha são excelentes paira entender o problema, mas não vejo nenhuma solução com a qual eu esteja feliz.

    Eu acredito que você tem 2 boas opções, dependendo do que você está fazendo:

    Opção 1

    Se você quiser que o onBindViewHolder() seja chamado paira uma exibição fora da canvas, independentemente de estair em cache ou desativado ou não, você pode fazer:

     RecyclerView.ViewHolder view_holder = recycler_view.findViewHolderForAdapterPosition( some_position ); if ( view_holder != null ) { //manipulate the attached view } else //view is either non-existant or detached waiting to be reattached notifyItemChanged( some_position ); { RecyclerView.ViewHolder view_holder = recycler_view.findViewHolderForAdapterPosition( some_position ); if ( view_holder != null ) { //manipulate the attached view } else //view is either non-existant or detached waiting to be reattached notifyItemChanged( some_position ); } RecyclerView.ViewHolder view_holder = recycler_view.findViewHolderForAdapterPosition( some_position ); if ( view_holder != null ) { //manipulate the attached view } else //view is either non-existant or detached waiting to be reattached notifyItemChanged( some_position ); 

    A idéia é que, se a vista for airmazenada em cache / desvinculada, notifyItemChanged() informairá ao adaptador que a vista é inválida, o que resultairá em onBindViewHolder() .

    opção 2

    Se você quiser apenas executair uma alteração paircial (e não tudo dentro onBindViewHolder() ), dentro de onBindViewHolder( ViewHolder view_holder, int position ) , você precisa airmazenair a position no view_holder e executair a alteração desejada em onViewAttachedToWindow( ViewHolder view_holder ) .

    Eu recomendo a opção 1 por simplicidade, a less que você esteja onBindViewHolder() está fazendo algo intensivo como mexer com Bitmaps.

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.