有點新手問題。我們爲什麼要初始化getView()
中的ViewHolder
?爲什麼我們不能在構造函數中初始化它?ViewHolder - 良好做法
回答
您將有多個ViewHolder
對象存在。
A ListView
其性質不會爲其每行創建新的View
實例。這是如此,如果你有一百萬件事情的ListView
,你不需要存儲一百萬件佈局信息。那麼你需要存儲什麼?只是在屏幕上的東西。然後,您可以重複使用這些視圖。這樣,您的ListView
百萬個對象可能只有10個子視圖。
在您的自定義陣列適配器,你將有一個名爲getView()
功能,看起來是這樣的:
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;
}
這是可行的,但需要一些時間,看看你是否可以在這裏發現的低效率。考慮一下上面哪段代碼會被重複調用。
問題是,我們一次又一次地打電話給row.findViewById
,即使第一次查找它後,它永遠不會改變。如果你的列表中只有一個簡單的TextView
,那麼它可能並不是那麼糟糕,如果你有一個複雜的佈局,或者你有多個你想要設置數據的視圖,你可能會失去一些時間來查找你的視圖,再次。
那麼我們如何解決這個問題呢?那麼,在我們查看之後將TextView存儲在某個地方是有意義的。所以我們引入一個名爲ViewHolder
的類,它可以「保留」視圖。所以適配器的內部,引入一個內部類,像這樣:
private static class ViewHolder {
TextView textView;
}
這個類是私有的,因爲它只是一個適配器一個緩存機制,所以我們並不需要的參考它是靜態的適配器來使用它。
這將存儲我們的視圖,以便我們不必多次撥打row.findViewById
。我們應該在哪裏設置它?當我們第一次誇大觀點時。我們在哪裏存儲它?視圖有一個自定義的「標籤」字段,可用於存儲關於視圖的元信息 - 正是我們想要的!然後,如果我們已經看到了這種觀點,我們只需要查找的標籤,而不是查找每個行內觀點..
所以getView()
內部的if語句變成:
//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();
}
現在,我們只需更新holder.textView的文本值,因爲它已經是對回收視圖的引用了!所以我們的最終適配器代碼變爲:
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;
}
我們完成了!
有些事情要考慮:
- 如何做到這一點的變化,如果你有要更改行多個視圖?作爲一個挑戰,讓一個ListView每行有兩個
TextView
對象和ImageView
- 當調試的ListView,查了幾件事情,讓你可以真正看到發生了什麼事情:
- 多少次ViewHolder的構造函數被調用。
- 的
holder.textView.getText()
價值是什麼,你在getView()
正如我們每次滾動列表時填充行併爲每行創建新行視圖,我們都需要初始化視圖持有者。就像我有兩行TextView然後,
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;
}
不,每個視圖都有不同的值。因爲我們在行中有不同的數據。 –
- 1. jquery良好做法
- 2. 良好做法MVC
- 3. MVVM的良好做法?
- 4. 良好做法在Perl
- 5. 良好做法:JDBC連接
- 6. IOS FMDB良好做法
- 7. $ elemMatch和良好做法
- 8. 繼承和良好做法
- 9. 演員的良好做法?
- 10. 良好的做法或不好的做法
- 11. Bundle Node.js後端 - 良好的做法或不好的做法?
- 12. ASP.NET MVC視圖模型良好做法
- 13. 日誌記錄良好做法
- 14. 排版模板或良好做法
- 15. 良好的做法默認值
- 16. 條件聲明中的良好做法
- 17. 寧靜的API,良好的做法
- 18. 識別iCloud coreData更新:良好做法
- 19. CSS的良好做法 - 每頁一頁?
- 20. 使用表格的良好做法
- 21. 的IEnumerable和良好做法(WCF)
- 22. 使用#define,良好的做法?
- 23. Bootstrap網格佈局良好做法
- 24. CodeIgniter:表單驗證良好做法
- 25. 定義PHP類時的良好做法
- 26. 編寫junit測試的良好做法
- 27. iPhone應用文檔的良好做法
- 28. ASP.NET MVC - DbContext的良好做法
- 29. 靜態存儲庫:良好的做法?
- 30. html的CSS設計良好的做法?
http://www.youtube.com/watch?v=wDBM6wVEO70年底更新之前。看看這個視頻。應該回答你的問題。 – Raghunandan