woff 發表於 2016-6-1 00:47:00

Android中ViewHolder的使用

Android中GridView和ListView是最重要的兩種顯示內容的控件,在Android中,受限於手機屏幕的大小,使的不能像電腦一樣同時顯示多項內容。
   這兩者都需要一個adapter,可以是自定義適配器,也可以是BaseAdapter,SimpleAdapter,CursorAdapter。自定義適配器中,最為重要的是getView()方法,在該方法中有一個convertView參數,該參數就是用來加載數據時的View。
    在ListView中有時我們需要加載大量數據,如果每次都創建一個View,這樣會佔據大量內存,影響性能。這時就可以考慮用ViewHolder了。
      ViewHolder不是Android的開發API,而是一種設計方法,就是設計個靜態類,緩存一下,省得Listview更新的時候,還要重新操作。
下面以listView加載方式比較一下viewholder的便利。
viewholder的方式:將convetView的tag設置為ViewHolder,不為空時重新使用即可:


classViewHolder{
                        ImageView img;
                        TextViewsitekey;
                        TextView partname;
                        TextView price;
                        TextView value;
                        TextView quantity_sold;
                        TextView end_date;
                        TextView jiantou;
                }

public View getView(int position, View convertView, ViewGroup parent) {
                        ViewHolder holder = new ViewHolder();
                        if(convertView==null){
                                convertView = inflater.inflate(R.layout.good_list_item, null, false);
                                holder.img = (ImageView) convertView.findViewById(R.id.img);
                                holder.sitekey = (TextView) convertView.findViewById(R.id.sitekey);
                                holder.partname = (TextView) convertView.findViewById(R.id.partname);
                                holder.price = (TextView) convertView.findViewById(R.id.price);
                                holder.value = (TextView) convertView.findViewById(R.id.value);
                                holder.quantity_sold = (TextView) convertView.findViewById(R.id.quantity_sold);
                                holder.end_date = (TextView) convertView.findViewById(R.id.end_date);
                                holder.jiantou = (TextView) convertView.findViewById(R.id.jiantou);
                                convertView.setTag(holder);
                        }else{
                                holder = (ViewHolder) convertView.getTag();
                        }
                        //设置holder
                        holder.img.setImageResource(R.drawable.ic_launcher);
                        holder.sitekey.setText(list.get(position).sitekey);
                        holder.partname.setText(list.get(position).partname);
                        holder.price.setText("$"+list.get(position).price);
                        holder.value.setText("$"+list.get(position).value);
                        holder.quantity_sold.setText("已售出:"+list.get(position).quantity_sold);
                        holder.end_date.setText("截止日期:"+list.get(position).end_date);
                       
                       
                        return convertView;
                }錯誤的加載方式:每一次都重新定義一個View載入佈局,再加載數據:
public View getView(int position, View convertView, ViewGroup parent) {
View item = mInflater.inflate(R.layout.list_item_icon_text, null);
((TextView) item.findViewById(R.id.text)).setText(DATA);
((ImageView) item.findViewById(R.id.icon)).setImageBitmap(
(position & 1) == 1 ? mIcon1 : mIcon2);
return item;
}正確的加載:當convertView不為空的時候直接重新使用convertView從而減少了很多不必要的View的創建,然後加載數據。
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item, parent, false);
}
((TextView) convertView.findViewById(R.id.text)).setText(DATA);
((ImageView) convertView.findViewById(R.id.icon)).setImageBitmap(
(position & 1) == 1 ? mIcon1 : mIcon2);
return convertView;
}convertView在API中的解釋是The old view to reuse, if possible,第一次getView時還沒有convertView,這時你便創建了一個新的view,下次getView時就有這個“舊的”convertView了setTag的作用才是把查找的view通過ViewHolder封裝好緩存起來方便 ​​多次重用,當需要時可以getTag拿出來
當你的listview里布局多樣化的時候viewholder的作用就有比較明顯的體現了。當然了,單一模式的佈局一樣有性能優化的作用只是不直觀。假如你2種模式的佈局當發生回收的時候你會用setTag分別記錄是哪兩種這兩種模式會被封裝到viewholder中進行保存方便你下次使用。所以當加載大量數據時,最好使用ViewHolder。
頁: [1]
查看完整版本: Android中ViewHolder的使用