Quel est l'avantage de ViewHolder?
lorsque vous développez un programme Android; et vous voulez avoir un ArrayAdapter vous pouvez simplement avoir une classe (la plupart du temps avec ViewHolder suffixe) ou gonfler directement votre convertView et trouver votre vue par id.
Quel est donc l'avantage d'utiliser le viseur?
L'exemple des deux ici :
if(convertView==null)
{
convertView = ((Activity)_context).getLayoutInflater().inflate(R.layout.row_phrase, null);
}
((TextView)convertView.findViewById(R.id.txtPhrase)).setText("Phrase 01");
Ou:
static class ViewHolder {
ImageView leftIcon;
TextView upperLabel;
TextView lowerLabel;
}
et enfin dans le 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);
4 réponses
comprendre comment fonctionne listview recycling
Comment fonctionne le mécanisme de recyclage de ListView
vous ne pouvez pas recycler une rangée qui est actuellement utilisée. Le lien ci-dessus explique comment fonctionne le mécanisme de recyclage listview
alors quel est l'avantage d'utiliser le viseur?
citant docs
votre code pourrait appeler findViewById()
souvent pendant le défilement de ListView, ce qui peut ralentir la performance. Même lorsque l'Adaptateur renvoie une vue gonflée pour Recyclage, vous devez quand même rechercher les éléments et les mettre à jour. Une façon de contourner l'utilisation répétée de findViewById()
est d'utiliser le dessin de" vue 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;
}
vous avez manqué la partie importante convertView.setTag(holder)
et holder = (ViewHolder) ConvertView.getTag()
http://developer.android.com/training/improving-layouts/smooth-scrolling.html
ViewHolder
design pattern est utilisé pour accélérer le rendu de votre ListView
- en fait pour le faire fonctionner en douceur, findViewById est assez cher (il fait DOM parsing) lorsqu'il est utilisé chaque fois qu'un élément de liste est rendu, il doit traverser votre hiérarchie de mise en page et aussi instancier des objets . Étant donné que les listes peuvent reformuler leurs articles assez fréquemment au cours du défilement, ces frais généraux peuvent être importants.
, vous pouvez trouver une bonne explication de la façon dont travaille :
http://www.youtube.com/watch?v=wDBM6wVEO70&feature=youtu.be&t=7m
à partir de la minute 10, vous avez expliqué le modèle de conception de titulaire de vue par les experts de google.
[modifier]
findViewById n'instancie pas de nouveaux objets, il ne traverse que la hiérarchie - voici la référence http://androidxref.com/5.1.1_r6/xref/frameworks/base/core/java/android/view/ViewGroup.java#3610
pendant que vous flânez dans votre ListView, il n'y a qu'une poignée de vues affichées à un moment donné. Cela signifie que vous n'avez pas à instancier une vue pour chaque élément de votre adaptateur; lorsqu'une vue s'éteint, elle peut être réutilisée, ou recyclé .
voir recyclage et le motif des présentoirs ne sont pas les mêmes. Le motif des voyants est uniquement pour réduire le nombre d'appels view.findViewById(int)
que vous faites. Le motif des visualiseurs seulement fonctionne lorsque vous profitez de vue recyclage.
dans getView(int position, View convertView, ViewGroup parent)
, le paramètre convertView
est soit null soit c'est une vue qui a été recyclée: il aura toujours les données d'un élément de liste différent lié à elle.
sans le motif du viseur, vous pouvez toujours profiter du recyclage de la vue (c'est-à-dire non instanciation aveugle des vues):
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;
}
ci-Dessus est un exemple de vue recyclage - nous ne gonflons pas une nouvelle vue pour chaque rangée; nous gonflons seulement une vue si nous ne sommes pas donnés à réutiliser. éviter d'avoir à gonfler une vue est la partie qui aidera certainement avec la performance lors de la défilement à travers votre liste: profitez du recyclage de vue.
alors, à quoi sert le viseur? Nous faisons actuellement 4x findViewById(int)
pour chaque article, indépendamment du fait que la rangée elle-même existait déjà. Comme findViewById(int)
itère récursivement vers le bas d'un groupe de vue jusqu'à ce qu'il trouve un descendant avec L'ID donné, c'est un peu inutile pour nos vues recyclées - nous retrouvons des vues que nous avons déjà des références.
évitez cela en utilisant un objet ViewHolder pour conserver les références aux sous-vues après que vous les "trouvez":
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)
vous permet de dire à la Vue de tenir un objet arbitraire. Si nous l'utilisons pour tenir une instance de notre Afficheur après avoir fait nos appels findViewById(int)
, nous pouvons utiliser View.getTag()
sur les vues recyclées pour éviter d'avoir à faire les appels encore et encore.
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);
}
les avantages de performance de cette optimisation sont discutables , mais c'est le avantage du titulaire de la vue .
premièrement:
dans ListView
lorsque vous faites défiler le ListView
vous devez créer un nouvel article et lier ses données sur elle si vous avez beaucoup d'articles dans ListView
il peut causer des fuites de mémoire parce que plus d'objets que vous avez créé pour les articles , mais Android en utilisant le concept de recycle la plupart de son API , et il signifie que vous créez un objet et l'utilisez au lieu de le détruire et de déclarer nouveau, donc, lorsque vous faites défiler ListView
API en utilisant les éléments invisibles que vous scrolled et passez-le pour vous dans getView
méthode il est convertView
donc ici, vous dealez avec plus d'articles ListView
Deuxièmement:
si vous avez un article personnalisé dans ListView
vous devez joindre votre disposition personnalisée sur chaque article du ListView
de sorte que vous serez à chaque fois ListView
lier nouvel article en utilisant findViewById
pour obtenir la référence des éléments de la disposition. Cette méthode ira à la recherche de votre article de manière récursive donc vous ViewHolder
vous aidera pour faire le récursif fait pour une fois seulement et puis il tiendra la référence de l'élément de mise en page pour vous jusqu'à ce que vous pouvez le joindre pour ListView
espère que cela vous aidera et me nourrir de retour dans tout pas chose évidente