OnBindViewHolder () nunca se llama en vista en posición aunque RecyclerView.findViewHolderForAdapterPosition () devuelve null en esa posición

Tengo una lista con 13 artículos (aunque los artículos se pueden agregar o quitar), posiciones 0-12. Cuando se muestra primero el fragmento que contiene el RecyclerView, sólo las posiciones 0 a 7 son visibles para el usuario (la posición 7 es sólo la mitad visible). En mi adaptador I Log cada vez que un sostenedor de la visión es binded / bound (idk si la gramática se aplica aquí) y registra su posición.

Adaptador

 @Override public void onBindViewHolder(final ViewHolder holder, final int position) { Log.d(TAG, "onBindViewHolder() position: " + position); ... } 

Desde mi Log veo que las posiciones 0-7 están enlazadas:

Registro desde el adaptador

Tengo un método selectAll() que obtiene cada ViewHolder por la posición del adaptador. Si el holder devuelto NO es null , utilizo el holder devuelto para actualizar la vista para mostrar que está seleccionado. Si el titular devuelto es null llamo a selectOnBind() un método que selectOnBind() la vista en esa posición para mostrar que está seleccionada cuando está enlazada en vez de en tiempo real, ya que no se muestra en la actualidad:

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

En este método I Log el holder junto con su posición:

Registro de selectAll ()

Así que hasta este punto todo parece normal. Tenemos posiciones 0-7 mostrando, y de acuerdo con el Log estas son las posiciones enlazadas. Cuando toco selectAll() sin cambiar las vistas visibles (desplazamiento) veo que las posiciones 0-7 están definidas y 8-12 son null . Hasta aquí todo bien.

Aquí es donde se pone interesante. Si después de llamar a selectAll() me selectAll() más abajo en la lista, las posiciones 8 y 9 no muestran que están seleccionadas.

Cuando compruebo el Log veo que es porque nunca se atan aunque fueron divulgados para ser null :

Registro del adaptador después del desplazamiento

Aún más confuso es que esto no sucede cada vez. Si primero lanzo la aplicación y prueba esto puede funcionar. Pero parece que sucede sin falta después. Supongo que tiene algo que ver con las opiniones que se están reciclando, pero aún así no tendrían que estar obligados?

EDIT (6-29-16)
Después de una actualización de AndroidStudio no puedo reproducir el error. Funciona como esperaba, vinculando las vistas nulas. Si este problema vuelve a aparecer, volveré a este mensaje.

Esto está sucediendo porque:

  • Las vistas no se agregan al recyclerview ( getChildAt no funcionará y devolverá null para esa posición)
  • También se almacenan en caché ( onBind no se llamará)

La llamada a recyclerView.setItemViewCacheSize(0) solucionará este "problema".

Debido a que el valor predeterminado es 2 ( private static final int DEFAULT_CACHE_SIZE = 2; en RecyclerView.Recycler ), siempre obtendrá 2 vistas que no llamarán onBind pero que no se agregan al reciclador

En su caso, las vistas para las posiciones 8 y 9 no se están reciclando, se están separando de la ventana y se volverán a conectar. Y para estas vistas separadas onBindViewHolder no se llama, sólo onViewAttachedToWindow se llama. Si anula estas funciones en su adaptador, puede ver lo que estoy hablando.

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

Ahora, con el fin de resolver su problema que necesita para realizar un seguimiento de las opiniones que se suponía que se recicla, pero se desprenden y luego hacer su proceso de sección en

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

Creo que jugar con la vista no es una buena idea en recyclerview. El acercamiento que utilizo siempre para seguir apenas para introducir una bandera al modelo usando para RecyclerView. Supongamos que su modelo es como –

 class MyModel{ String name; int age; } 

Si está realizando un seguimiento, la vista está seleccionada o no, a continuación, introduzca un booleano en el modelo. Ahora se verá como –

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

Ahora su casilla de verificación será seleccionada / no seleccionada sobre la base de la nueva bandera isSelected (en onBindViewHolder ()). En cada selección en vista cambiará el valor del valor seleccionado del modelo correspondiente a verdadero, y en no seleccionado cambiará a falso. En su caso, ejecute un bucle para cambiar el valor isSelected de todo el modelo a true y luego llame a notifyDataSetChanged() .

Por ejemplo, supongamos que su lista es

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

Mi sugerencia, al usar recyclerView o ListView para intentar menos jugar con vistas.

Así que en su caso –

 @Override 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); ... } @Override public void onClick(View view){ int position = (int)view.getTag(); recyclerList.get(position).isSelected = !recyclerList.get(position).isSelected; } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { int position = (int)buttonView.getTag(); recyclerList.get(position).isSelected = isChecked; } 

Espero que te ayude, por favor, hágamelo saber si necesita más explicación 🙂

Así que creo que la pregunta es contestada por @Pedro Oliveira. El principal sentido de RecycleView, que utiliza algoritmos especiales para almacenar en caché ViewHolder en cualquier momento. Así que next onBindViewHolder (…) puede no funcionar, por ejemplo. Si la vista es estática, o algo más.

Y sobre su pregunta que piensa utilizar RecycleView para las vistas cambiadas dinámicamente. NO LO HAGA! Porque RecycleView invalida vistas y tiene sistema de caché, por lo que tendrá muchos problemas.

Utilice LinkedListView para esta tarea!

  • ¿Es posible hacer que CursorAdapter se establezca en recycleview, al igual que ListView?
  • Cómo llamar a un método MainActivity de ViewHolder en RecyclerView.Adapter?
  • Desplazamiento horizontal y vertical en la vista del reciclador android
  • Activar la vista del reciclador
  • RecyclerView Sticky Header onClick y barra de desplazamiento
  • Cómo agregar el recyclerview al proyecto
  • ¿Por qué RecyclerView onBindViewHolder se llama una sola vez?
  • Adaptador RecyclerView que toma valores erróneos
  • ¿Existe un reemplazo para el widget Galería con Reciclado de vistas?
  • Cómo utilizar RecyclerView y CardView
  • Cómo establecer el elemento al centro de la vista Reciclador cuando se selecciona
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.