Tengo una ListView
que muestra noticias. Contienen una imagen, un título y algo de texto. La imagen se carga en un hilo separado (con una cola y todo) y cuando la imagen se descarga, ahora llamo notifyDataSetChanged()
al adaptador de la lista para actualizar la imagen. Esto funciona, pero getView()
se llama con demasiada frecuencia, ya que notifyDataSetChanged()
requiere getView()
todos los elementos visibles. Quiero actualizar solo el elemento individual de la lista. ¿Cómo haría esto?
Los problemas que tengo con mi enfoque actual son:
- El desplazamiento es lento
- Tengo una animación de aparición gradual en la imagen que ocurre cada vez que se carga una nueva imagen en la lista.
Esta pregunta se hizo en Google I / O 2010, puede verla aquí:
El mundo de ListView, hora 52:30
Básicamente lo que explica Romain individuo es llamar
getChildAt(int)
en elListView
para obtener la vista y llamada (creo)getFirstVisiblePosition()
para averiguar la correlación entre la posición y el índice.Romain también señala el proyecto llamado Shelves como un ejemplo, creo que podría referirse al método
ShelvesActivity.updateBookCovers()
, pero no puedo encontrar la llamadagetFirstVisiblePosition()
.ACTUALIZACIONES IMPRESIONANTES VENIDAS:
RecyclerView solucionará esto en un futuro próximo. Como se señaló en http://www.grokkingandroid.com/first-glance-androids-recyclerview/ , podrá llamar a métodos para especificar exactamente el cambio, como:
Además, todos querrán usar las nuevas vistas basadas en RecyclerView porque serán recompensados con animaciones de aspecto agradable. ¡El futuro se ve increíble! :-)
fuente
Así es como lo hice:
Sus elementos (filas) deben tener identificadores únicos para que pueda actualizarlos más tarde. Establezca la etiqueta de cada vista cuando la lista obtenga la vista del adaptador. (También puede usar la etiqueta clave si la etiqueta predeterminada se usa en otro lugar)
Para la actualización, verifique cada elemento de la lista, si hay una vista con una ID dada, es visible, por lo que realizamos la actualización.
¡En realidad es más fácil que otros métodos y mejor cuando se trata de identificadores, no de posiciones! También debe llamar a la actualización para los elementos que se hacen visibles.
fuente
obtener la clase de modelo primero como global como este objeto de clase de modelo
e inicializarlo a global
obtener la fila actual de la vista por el modelo inicializándola en el modelo global
establezca el valor cambiado en el método de objeto de modelo global que se establecerá y agregue el método notifyDataSetChanged para mí.
Aquí hay una pregunta relacionada sobre esto con buenas respuestas.
fuente
Las respuestas son claras y correctas, agregaré una idea para el
CursorAdapter
caso aquí.Si está subclasificando
CursorAdapter
(oResourceCursorAdapter
, oSimpleCursorAdapter
), puede implementarViewBinder
o anularbindView()
ynewView()
métodos, estos no reciben el índice del elemento de la lista actual en los argumentos. Por lo tanto, cuando llegan algunos datos y desea actualizar los elementos de la lista visible relevante, ¿cómo sabe sus índices?Mi solución era:
newView()
notifyDatasetChanged()
y actualizarlos todosDebido al reciclaje de vistas, la cantidad de referencias de vista que necesitaré almacenar e iterar será aproximadamente igual a la cantidad de elementos de la lista visibles en la pantalla.
fuente
Para RecycleView, use este código
fuente
Utilicé el código que proporcionó a Erik, funciona muy bien, pero tengo un adaptador personalizado complejo para mi vista de lista y me enfrenté a dos veces la implementación del código que actualiza la interfaz de usuario. Intenté obtener la nueva vista del método getView de mis adaptadores (la lista de arrays que contiene los datos de la vista de lista ya se ha actualizado / cambiado):
Está funcionando bien, pero no sé si es una buena práctica. Por lo tanto, no necesito implementar el código que actualiza el elemento de la lista dos veces.
fuente
exactamente usé esto
fuente
Creé otra solución, como el método RecyclyerView void
notifyItemChanged(int position)
, creo la clase CustomBaseAdapter así:No olvides crear una clase CustomDataSetObservable también para la
mDataSetObservable
variable en CustomAdapterClass , como esta:en la clase CustomBaseAdapter hay un método
notifyItemChanged(int position)
, y puede llamar a ese método cuando desee actualizar una fila donde lo desee (desde el clic del botón o desde cualquier lugar donde desee llamar a ese método). Y listo, tu fila individual se actualizará instantáneamente.fuente
Mi solución: si es correcto *, actualice los datos y los elementos visibles sin volver a dibujar la lista completa. De lo contrario, notifiqueDataSetChanged.
Correcto: tamaño de datos antiguos == tamaño de datos nuevo e ID de datos antiguos y su orden == ID de datos nuevos y orden
Cómo:
y por supuesto:
Ignore el último parámetro para bindView (lo uso para determinar si necesito o no reciclar mapas de bits para ImageDrawable).
Como se mencionó anteriormente, el número total de vistas "visibles" es aproximadamente la cantidad que cabe en la pantalla (ignorando los cambios de orientación, etc.), por lo que no es una gran memoria.
fuente
Además de esta solución ( https://stackoverflow.com/a/3727813/5218712 ) solo quiero agregar que debería funcionar solo si
listView.getChildCount() == yourDataList.size();
podría haber una vista adicional dentro de ListView.Ejemplo de cómo se completan los elementos secundarios:
fuente