Małe pytanie dla początkujących. Dlaczego powinniśmy zainicjować ViewHolder
w getView()
? Dlaczego nie możemy zainicjować tego w konstruktorze?ViewHolder - dobra praktyka
Odpowiedz
Będziesz mieć wiele ViewHolder
obiektów w istnieniu.
Ze względu na swój charakter nie tworzy nowych instancji View
dla każdego z jego wierszy. Jest tak, że jeśli masz milion rzeczy, nie musisz przechowywać informacji o układzie na milion rzeczy. Co więc chcesz przechowywać? Tylko rzeczy, które są na ekranie. Możesz następnie ponownie wykorzystać te widoki. W ten sposób twój ListView
z miliona obiektów może mieć po prostu 10 widoków potomnych.
W niestandardowego adaptera tablicy, trzeba będzie funkcję o nazwie getView()
, który wygląda mniej więcej tak:
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;
}
to będzie działać, ale poświęć chwilę i sprawdzić, czy można dostrzec nieefektywność tutaj. Zastanów się, który z powyższych kodów zostanie nazwany redundantnie.
Problem polega na tym, że wzywamy row.findViewById
w kółko, mimo że po raz pierwszy sprawdzimy to, nigdy się nie zmieni. Jeśli masz tylko prostą TextView
na liście, to prawdopodobnie nie jest tak źle, jeśli masz złożony układ lub masz wiele widoków, dla których chcesz ustawić dane, możesz stracić trochę czasu na znajdowaniu widoku i jeszcze raz.
Jak to naprawić? Cóż, sensownym byłoby przechowywanie tego TextView gdzieś po sprawdzeniu. Wprowadzamy więc klasę o nazwie ViewHolder
, która "zatrzymuje" widoki. Więc wewnątrz zasilacza, wprowadzić wewnętrzną klasę tak:
private static class ViewHolder {
TextView textView;
}
Ta klasa jest prywatny, ponieważ jest to po prostu mechanizm buforowania dla adaptera, a to jest statyczne, dzięki czemu nie musimy odniesienie do adapter, aby z niego korzystać.
Spowoduje to zapisanie naszego widoku, abyśmy nie musieli wielokrotnie dzwonić pod numer row.findViewById
. Gdzie powinniśmy go ustawić? Kiedy podnosimy widok po raz pierwszy. Gdzie go przechowujemy? Widoki mają niestandardowe pole "znacznik", które może służyć do przechowywania meta-informacji o widoku - dokładnie tego, co chcemy! Następnie, jeśli już widzieliśmy ten pogląd, musimy tylko patrzeć tag zamiast patrząc na każdego z widoków w obrębie rzędu ..
So if wewnątrz getView()
staje:
//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();
}
Teraz musimy po prostu zaktualizować wartość tekstową holder.textView, ponieważ jest to już odniesienie do widoku z recyklingu! Więc nasz kod ostatniego adaptera staje się następujący:
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;
}
Skończyliśmy!
Niektóre rzeczy o tym myśleć:
- W jaki sposób ta zmiana, jeśli masz wiele widoków w wierszu, który chcesz zmienić? Jako wyzwanie, uczynić ListView, gdzie każdy wiersz ma dwa
TextView
obiektów iImageView
- Podczas debugowania ListView, sprawdzić kilka rzeczy, dzięki czemu można naprawdę zobaczyć, co się dzieje:
- Ile razy konstruktor ViewHolder nazywa .
- Co wartość
holder.textView.getText()
to zanim go zaktualizować na koniecgetView()
thnx, wspaniała odpowiedź – Gorets
Nie ma problemu - daj mi znać, jeśli wszystko ma sens, funkcja ViewHolder na chwilę mnie zmyliła, gdy po raz pierwszy się o tym dowiedziałem. – mindvirus
Wow. Doskonała odpowiedź. Jako wyzwanie dla ciebie; czy możesz to poprawić dzięki niektórym referencjom? =) – Qw4z1
Gdy przewijamy listę za każdym razem, gdy wypełniamy wiersz, a dla każdego wiersza tworzony jest nowy widok wiersza, musimy zainicjować uchwyt widoku. Podobnie jak mam dwa TextView w rzędzie wtedy
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;
}
Nie, każdy wzorzec ma różne wartości. Ponieważ mamy różne dane w rzędzie. –
- 1. Dobra praktyka do wielowątkowości
- 2. Delphi - FieldByName.AsString - dobra praktyka
- 3. Dobra praktyka czy zła praktyka wymuszania na HTTPS całej witryny?
- 4. Używanie wyrażenia using z WinForms ... Dobra praktyka?
- 5. Deklaracja podziału i przypisanie = Dobra praktyka?
- 6. AsyncTask wewnątrz metody statycznej - Dobra praktyka kodowania?
- 7. Dobra praktyka: porządkowanie views.py w aplikacjach Django
- 8. ASP.NET MVC - TempData - dobra czy zła praktyka
- 9. Przepełnienie tablicy bloków znaków, dobra praktyka?
- 10. Projektowanie dziedziczenia przy użyciu interfejsu + klasa abstrakcyjna. Dobra praktyka?
- 11. Dobra praktyka używania odwrotnych indeksów na kluczach zastępczych? (Oracle)
- 12. Czy istnieje dobra praktyka, gdy typ powinien być zapakowany?
- 13. Implementacja kolejki C za pomocą void * - dobra lub zła praktyka?
- 14. Co to jest dobra praktyka podczas pisania modułu node.js
- 15. Logika w celu uzyskania części własności. Dobra praktyka?
- 16. perl (dobra praktyka): uchwyt pliku leksykalnego dla gniazda
- 17. Anulowanie wątku za pomocą pthread_cancel: dobra praktyka lub zła
- 18. Dobra praktyka: Domyślne argumenty dla czystej wirtualnej metody
- 19. Czy pojedynczy plik logback.xml dla wielu aplikacji to dobra praktyka?
- 20. Co to jest dobra praktyka do generowania szczegółowych wyników?
- 21. Dobra praktyka: 301 Przekieruj HTTP do HTTPS (standardowa domena)
- 22. Dlaczego we wzorcu ViewHolder klasa ViewHolder powinna być statyczna?
- 23. Pole wyboru ViewView Viewholder:
- 24. Android Viewholder dla ViewPager
- 25. Dlaczego RecyclerView.notifyItemChanged() utworzy nowy ViewHolder i użyje zarówno starego ViewHolder, jak i nowego?
- 26. Czy dla wydajności parametr ViewHolder ma być statyczny we wzorcu ViewHolder?
- 27. Parametr Android ViewHolder z RecyclerView # onCreateViewHolder differents
- 28. Aktualizacja adaptera RecyclerView i ViewHolder dynamicznie
- 29. ViewHolder wzór poprawnie zaimplementowany w niestandardowym CursorAdapter?
- 30. Dobra lub zła praktyka dla okien dialogowych w WPF z MVVM?
http://www.youtube.com/watch?v=wDBM6wVEO70. Obejrzyj ten film. Powinien odpowiedzieć na twoje pytanie. – Raghunandan