¿Cuál es el beneficio de ViewHolder?
Cuando esté desarrollando un programa de Android; Y usted desea tener un ArrayAdapter usted puede tener simplemente una clase (la mayoría de veces con el sufijo de ViewHolder ) o inflar directamente su convertView y encontrar su opinión por el id.
¿Cuál es el beneficio de usar ViewHolder?
El ejemplo de ambos aquí:
if(convertView==null) { convertView = ((Activity)_context).getLayoutInflater().inflate(R.layout.row_phrase, null); } ((TextView)convertView.findViewById(R.id.txtPhrase)).setText("Phrase 01");
O:
- Interacción de ExpandableListAdapter.getChildView () con AbsListView.LayoutParams
- Eliminar el separador ListView (en el archivo de diseño xml)
- La posición de la vista de lista se cambia al desplazarse en android
- Cómo hacer TextWatcher esperar un tiempo antes de hacer algo de acción
- ¿Cómo puedo obtener un elemento ListView para ser elevado?
static class ViewHolder { ImageView leftIcon; TextView upperLabel; TextView lowerLabel; }
Y finalmente en el getView:
ViewHolder holder = null; if (view == null) { view = LayoutInflater.from(context).inflate(R.layout.row_layout, null, false); holder = new ViewHolder(); holder.leftIcon = (ImageView) view.findViewById(R.id.leftIcon);
- La selección de ListView permanece persistente después de salir del modo de selección
- Ormlite, listViews y adaptadores?
- El primer elemento de un ListView no funciona correctamente en Android
- Omitir una fila en la vista de lista
- Actualizar fragmento actual (datos ListView) que permanece en la misma actividad
- Android: Cómo medir la altura total de ListView
- Android ListView scrollTo
- Obtener elementos seleccionados de ListView con casilla de verificación
Entender cómo funciona el reciclaje listview
Cómo funciona el mecanismo de reciclaje de ListView
No puede reciclar una fila que esté actualmente en uso. El enlace anterior explica cómo funciona el mecanismo de reciclado listview
¿Cuál es el beneficio de usar ViewHolder?
Citando documentos
Su código puede llamar a findViewById()
frecuencia durante el desplazamiento de ListView, lo que puede ralentizar el rendimiento. Incluso cuando el adaptador devuelve una vista inflada para reciclar, todavía necesita buscar los elementos y actualizarlos. Una forma de evitar el uso repetido de findViewById()
es usar el patrón de diseño "view holder".
public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { // if convertView is null convertView = mInflater.inflate(R.layout.mylayout, parent, false); holder = new ViewHolder(); // initialize views convertView.setTag(holder); // set tag on view } else { holder = (ViewHolder) convertView.getTag(); // if not null get tag // no need to initialize } //update views here return convertView; }
Se ha perdido la parte importante convertView.setTag(holder)
y holder = (ViewHolder) ConvertView.getTag()
http://developer.android.com/training/improving-layouts/smooth-scrolling.html
ViewHolder
patrón de diseño de ViewHolder
se utiliza para acelerar la representación de tu ListView
– en realidad para que funcione sin problemas, findViewById es bastante costoso (se analiza el DOM) cuando se utiliza cada vez que se representa un elemento de lista, debe desplazar la jerarquía de diseño y también instanciar objetos . Dado que las listas pueden volver a dibujar sus elementos con bastante frecuencia durante el desplazamiento, tales gastos generales podrían ser sustanciales.
Usted puede encontrar una buena explicación de cómo esto funciona en:
http://www.youtube.com/watch?v=wDBM6wVEO70&feature=youtu.be&t=7m
A partir del minuto 10, usted ha explicado el patrón de diseño ViewHolder por los expertos de google.
[editar]
FindViewById no está instanciando nuevos objetos, solo atraviesa la jerarquía – aquí está la referencia http://androidxref.com/5.1.1_r6/xref/frameworks/base/core/java/android/view/ViewGroup.java#3610
A medida que avanza a través de su ListView, sólo hay un puñado de puntos de vista que se muestran en un momento dado. Esto significa que no tiene que instanciar una vista para cada elemento de su adaptador; Cuando una vista se desplaza fuera de la pantalla, puede ser reutilizada o reciclada .
El reciclado de la vista y el patrón ViewHolder no son los mismos. El patrón ViewHolder es únicamente para reducir el número de view.findViewById(int)
que realiza. El patrón ViewHolder sólo funciona cuando se aprovecha el reciclaje de vistas.
En getView(int position, View convertView, ViewGroup parent)
, el parámetro convertView
es nulo o es una vista que se ha reciclado: todavía tendrá los datos de un elemento de lista diferente vinculado a él.
Sin el patrón ViewHolder, todavía puede aprovechar el reciclado de la vista (es decir, no crear instancias de vistas de forma ciega):
public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (view == null) { view = // inflate new view } ImageView imageView = (ImageView) view.findViewById(R.id.listitem_image); TextView textView = (TextView) view.findViewById(R.id.listitem_text); TextView timestampView = (TextView) view.findViewById(R.id.listitem_timestamp); ProgressBar progressSpinnerView = (ProgressBar) view.findViewById(R.id.progress_spinner); // TODO: set correct data for this list item // imageView.setImageDrawable(...) // textView.setText(...) // timestampView.setText(...) // progressSpinnerView.setProgress(...) return view; }
Arriba se muestra un ejemplo de reciclaje de vistas: no inflaremos una nueva vista para cada fila; Sólo inflamos una vista si no nos dan uno para reutilizar. Evitar tener que inflar una vista es la parte que definitivamente ayudará con el rendimiento al desplazarse por su lista: aproveche el reciclado de la vista.
Entonces, ¿cuál es el ViewHolder para entonces? Actualmente estamos haciendo 4x findViewById(int)
para cada elemento, independientemente de si la fila misma ya existía. Como findViewById(int)
itera recursivamente un ViewGroup hasta encontrar un descendiente con el ID dado, esto es un poco inútil para nuestras vistas recicladas – estamos buscando nuevas vistas a las que ya tenemos referencias.
Evite esto utilizando un objeto ViewHolder para mantener referencias a las sub-vistas después de "encontrarlas":
private static class ViewHolder { final TextView text; final TextView timestamp; final ImageView icon; final ProgressBar progress; ViewHolder(TextView text, TextView timestamp, ImageView icon, ProgressBar progress) { this.text = text; this.timestamp = timestamp; this.icon = icon; this.progress = progress; } }
View.setTag(Object)
permite decir a la Vista que contenga un objeto arbitrario. Si lo usamos para mantener una instancia de nuestro ViewHolder después de hacer nuestras findViewById(int)
, entonces podemos usar View.getTag()
en las vistas reciclado para evitar tener que hacer las llamadas una y otra vez.
public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (view == null) { view = // inflate new view ViewHolder holder = createViewHolderFrom(view); view.setTag(holder); } ViewHolder holder = view.getTag(); // TODO: set correct data for this list item // holder.icon.setImageDrawable(...) // holder.text.setText(...) // holder.timestamp.setText(...) // holder.progress.setProgress(...) return view; } private ViewHolder createViewHolderFrom(View view) { ImageView icon = (ImageView) view.findViewById(R.id.listitem_image); TextView text = (TextView) view.findViewById(R.id.listitem_text); TextView timestamp = (TextView) view.findViewById(R.id.listitem_timestamp); ProgressBar progress = (ProgressBar) view.findViewById(R.id.progress_spinner); return new ViewHolder(text, timestamp, icon, progress); }
Los beneficios de rendimiento de esta optimización son cuestionables , pero eso es el beneficio de ViewHolder .
En primer lugar :
En ListView
cuando se desplaza el ListView
necesita crear un nuevo elemento y enlazar sus datos en él así que si tiene muchos elementos en ListView
puede causar pérdida de memoria porque más objetos que ha creado para los elementos, pero Android con el concepto de reciclar la mayor parte de su API , Y lo que significa que crear un objeto y utilizarlo en lugar de destruirlo y declarar uno nuevo, por lo que cuando se desplaza API de ListView
utilizando los elementos invisibles que se despliegan y pasarlo para usted en el método convertView
es convertView
así que aquí usted trata con más elementos ListView
En segundo lugar:
Si tiene un elemento personalizado en ListView
, debe adjuntar el diseño personalizado en cada elemento del ListView
modo que cada vez que ListView
vincule el nuevo elemento utilizando findViewById
para obtener referencia de los elementos de diseño. Este método irá a buscar su artículo de manera recursiva para que ViewHolder
le ayudará a hacer el recursivo hecho por una sola vez y luego mantendrá la referencia del elemento de diseño para usted hasta que pueda adjuntarlo para ListView
Espero que esto le ayude y me alimente de nuevo en cualquier cosa no obvia
- Android-support-v4.jar no se importa correctamente en Eclipse
- Relleno izquierdo / derecho para Button.setCompoundDrawablesWithIntrinsicBounds ()?