Eine kleine Neuling Frage. Warum sollten wir die ViewHolder
in getView()
initialisieren? Warum können wir es nicht im Konstruktor initialisieren?ViewHolder - gute Praxis
Antwort
Sie werden mehrere ViewHolder
Objekte in Existenz.
Ein ListView
erstellt von Natur aus keine neuen View
Instanzen für jede Zeile. Dies ist so, dass, wenn Sie eine ListView
von einer Million Dinge haben, Sie Layout-Informationen für eine Million Dinge nicht speichern müssen. Was müssen Sie also speichern? Nur die Dinge, die auf dem Bildschirm sind. Sie können diese Ansichten dann immer wieder verwenden. Auf diese Weise kann Ihre ListView
einer Million Objekte nur vielleicht 10 Kindansichten haben.
In Ihrem benutzerdefinierten Array-Adapter, werden Sie eine Funktion getView()
, die etwa wie folgt aussieht genannt haben:
public View getView(int position, View convertView, ViewGroup parent) {
//Here, position is the index in the list, the convertView is the view to be
//recycled (or created), and parent is the ListView itself.
//Grab the convertView as our row of the ListView
View row = convertView;
//If the row is null, it means that we aren't recycling anything - so we have
//to inflate the layout ourselves.
if(row == null) {
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.list_item, parent, false);
}
//Now either row is the recycled view, or one that we've inflated. All that's left
//to do is set the data of the row. In this case, assume that the row is just a
//simple TextView
TextView textView = (TextView) row.findViewById(R.id.listItemTextView);
//Grab the item to be rendered. In this case, I'm just using a string, but
//you will use your underlying object type.
final String item = getItem(position);
textView.setText(item);
//and return the row
return row;
}
einen Moment Zeit und sehen Dies funktioniert, aber nehmen, wenn Sie die Ineffizienz hier erkennen. Denken Sie darüber nach, welcher der obigen Codes redundant genannt wird.
Das Problem ist, dass wir row.findViewById
immer und immer wieder aufrufen, obwohl nach dem ersten Mal wir es nachschlagen, wird es nie ändern. Wenn Sie nur eine einfache TextView
in Ihrer Liste haben, ist es wahrscheinlich nicht so schlimm, wenn Sie ein komplexes Layout haben oder mehrere Ansichten haben, für die Sie Daten festlegen möchten, könnten Sie ein wenig Zeit verlieren, Ihre Ansicht über und zu finden erneut.
Also, wie reparieren wir das? Nun, es würde Sinn machen, das TextView irgendwo zu speichern, nachdem wir es nachgeschlagen haben. Also stellen wir eine Klasse namens ViewHolder
vor, die die Ansichten "hält". Also innerhalb des Adapters einführte eine innere Klasse wie folgt:
private static class ViewHolder {
TextView textView;
}
Diese Klasse ist privat, da es nur ein Caching-Mechanismus für den Adapter ist, und es ist statisch, so dass wir keinen Hinweis auf die Notwendigkeit Adapter, um es zu benutzen.
Dies speichert unsere Ansicht, so dass wir row.findViewById
nicht mehrmals aufrufen müssen. Wo sollten wir es einstellen? Wenn wir die Ansicht zum ersten Mal aufblasen. Wo speichern wir es? Ansichten haben ein benutzerdefiniertes "Tag" -Feld, mit dem Meta-Informationen über die Ansicht gespeichert werden können - genau das, was wir wollen! Wenn wir dann schon diese Ansicht gesehen haben, haben wir nur den Tag zu sehen, anstatt jede der Ansichten innerhalb der Reihe aufzublicken ..
also die if-Anweisung innerhalb von getView()
wird:
//If the row is null, it means that we aren't recycling anything - so we have
//to inflate the layout ourselves.
ViewHolder holder = null;
if(row == null) {
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.list_item, parent, false);
//Now create the ViewHolder
holder = new ViewHolder();
//and set its textView field to the proper value
holder.textView = (TextView) row.findViewById(R.id.listItemTextView);
//and store it as the 'tag' of our view
row.setTag(holder);
} else {
//We've already seen this one before!
holder = (ViewHolder) row.getTag();
}
Nun müssen wir nur noch den Textwert von holder.textView aktualisieren, da es sich bereits um einen Verweis auf die recycelte Ansicht handelt! So wird unser endgültiger Adaptercode:
public View getView(int position, View convertView, ViewGroup parent) {
//Here, position is the index in the list, the convertView is the view to be
//recycled (or created), and parent is the ListView itself.
//Grab the convertView as our row of the ListView
View row = convertView;
//If the row is null, it means that we aren't recycling anything - so we have
//to inflate the layout ourselves.
ViewHolder holder = null;
if(row == null) {
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.list_item, parent, false);
//Now create the ViewHolder
holder = new ViewHolder();
//and set its textView field to the proper value
holder.textView = (TextView) row.findViewById(R.id.listItemTextView);
//and store it as the 'tag' of our view
row.setTag(holder);
} else {
//We've already seen this one before!
holder = (ViewHolder) row.getTag();
}
//Grab the item to be rendered. In this case, I'm just using a string, but
//you will use your underlying object type.
final String item = getItem(position);
//And update the ViewHolder for this View's text to the correct text.
holder.textView.setText(item);
//and return the row
return row;
}
Und wir sind fertig!
Einige Dinge denken:
- Wie funktioniert diese Änderung, wenn Sie mehrere Ansichten in einer Zeile, die Sie ändern möchten haben? Als Herausforderung, ein Listview machen, wobei jede Reihe zwei
TextView
Objekte und einImageView
- Wenn Ihre Listview-Debugging, überprüfen ein paar Dinge, so dass Sie wirklich sehen, was los ist:
- Wie oft ViewHolder Konstruktor aufgerufen wird .
- Was ist der Wert von
holder.textView.getText()
ist, bevor Sie es am Ende desgetView()
thnx, ehrfürchtige Antwort – Gorets
Kein Problem - lassen Sie mich wissen, wenn alles Sinn ergibt, verwirrte das ViewHolder-Ding mich definitiv eine Zeitlang, als ich zuerst darüber erfuhr. – mindvirus
Wow. Ausgezeichnete Antwort. Als eine Herausforderung für dich; Kannst du es mit einigen Referenzen verbessern? =) – Qw4z1
Beim Scrollen der Liste jedes Mal, wenn Zeilenauffüllung und neue Zeilenansicht für jede Zeile erstellt werden, müssen wir den Ansichtshalter initialisieren. Genau wie ich zwei Textview in Reihe haben, dann
static class ViewHolder {
protected TextView title;
protected TextView type;
}
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
view = inflator.inflate(R.layout.feeds_rowview, null);
final ViewHolder viewHolder = new ViewHolder();
view.setTag(viewHolder);
viewHolder.title = (TextView) view.findViewById(R.id.Title);
viewHolder.type = (TextView) view.findViewById(R.id.Type);
} else {
view = convertView;
}
ViewHolder holder = (ViewHolder) view.getTag();
holder.title.setText(list.get(position).getTitle());
holder.type.setText(list.get(position).getType());
return view;
}
Nein, Jeder Viewholder hat unterschiedliche Werte. Da wir die verschiedenen Daten in der Reihe haben. –
- 1. Gute Praxis Klasse Zeilenanzahl
- 2. ist eine gute Praxis
- 3. Relationales Datenbankdesign Gute Praxis: Normalisierung?
- 4. Gute Praxis um Seiten umzuleiten?
- 5. gute Praxis für Code-Flow?
- 6. PHP Gute Praxis der Kryptographie?
- 7. Wird mapM/sequenz als gute Praxis angesehen?
- 8. Datenbank Upserts - Gute oder schlechte Praxis?
- 9. ASP.NET MVC - TempData - gute oder schlechte Praxis
- 10. Verwendet MS SQL Identity gute Praxis?
- 11. Ist "Behauptung falsch"; eine gute Praxis?
- 12. Master-Include-Dateien - gute oder schlechte Praxis
- 13. Ist ein Beispiel für eine gute Praxis?
- 14. gute Praxis in C++ (faule Bewertung)
- 15. Provider Service oder Container injizieren. Gute Praxis
- 16. Shapes in E-Mails - eine gute Praxis?
- 17. viewHolder konnte nicht von viewHolder
- 18. Gute Praxis: Organisation von views.py in Django Apps
- 19. ist es gute Praxis, CallBacks Redux async Aktion zu übergeben?
- 20. Gute Praxis Weg zum Ausgang/Insert-post-Daten
- 21. Ist es eine gute Praxis, Variablen in Perl zu exportieren?
- 22. Websocket-basierte App, Sicherheit und gute Praxis in Echtzeit?
- 23. Java - Sortierung und csv: gute Praxis mit riesigen Daten
- 24. Ist "example.com/index.php/page/about/" eine gute Praxis?
- 25. Ist es eine gute Praxis, Variablen möglichst "final" zu deklarieren?
- 26. C-Queue-Implementierung mit void * - gute oder schlechte Praxis?
- 27. Warum ist es gute Praxis am Ende eines Verfahrens
- 28. Was ist eine gute Praxis für die Abhängigkeitsinjektion in Ruby?
- 29. Aktualisiere Reduzierer Anfangszustand mit localStorage Daten eine gute Praxis?
- 30. Sammeln Sie gemeinsame umfasst in einer einzigen Datei - gute Praxis?
http://www.youtube.com/watch?v=wDBM6wVEO70 aktualisieren. Schau dir dieses Video an. Sollte deine Frage beantworten. – Raghunandan