[原]Android開發優化-Adapter優化

雨知發表於2013-08-19

ListView作為Android開發中使用頻率最高的一個控制元件,保證ListView的流暢執行,對使用者體驗的提高至關重要。Adapter是ListView和資料來源之間的中間人,當每條資料進入可見區時,Adapter 的 getView() 會被呼叫,返回代表具體資料的檢視,在成百上千條資料觸控滾動時頻繁呼叫,因此如何優化Adapter是提高ListView效能的關鍵。

1. 使用ViewHolder模式,重複利用convertView,減少頻繁查詢

在2009年 Google IO開發者大會中已做說明,看一下使用不同實現方式之間的差距:

Adapter 顯示每條資料的 XML 佈局檔案如下:

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="horizontal"> 
    <ImageView android:id="@+id/icon" 
        android:layout_width="48dip" 
        android:layout_height="48dip" /> 
    <TextView android:id="@+id/text" 
        android:layout_gravity="center_vertical" 
        android:layout_width="0dip" 
        android:layout_weight="1.0" 
        android:layout_height="wrap_content" /> 
</LinearLayout>

1. 最慢最不實用的方式

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[position]);
	((ImageView) item.findViewById(R.id.icon)).setImageBitmap(
			(position & 1) == 1 ? mIcon1 : mIcon2);

	return item;
}

2. 使用 convertView 回收檢視, 效率提高 200%

public View getView(int position, View convertView, ViewGroup parent) { 
     if (convertView == null) { 
          convertView = mInflater.inflate(R.layout.item, null); 
     } 

     ((TextView) convertView.findViewById(R.id.text)).setText(DATA[position]); 
     ((ImageView) convertView.findViewById(R.id.icon)).setImageBitmap( 
               (position & 1) == 1 ? mIcon1 : mIcon2); 

     return convertView; 
}

3. 使用 ViewHolder 模式, 效率再提高 50%

static class ViewHolder { 
	TextView text; 
	ImageView icon; 
} 
public View getView(int pos, View convertView, ViewGroup parent){ 
    ViewHolder holder; 
    if (convertView == null) { 
        convertView = mInflater.inflate(R.layout.list_item, null); 
        holder = new ViewHolder();  
        holder.text = (TextView) convertView.findViewById(R.id.text)); 
        holder.icon = (ImageView) convertView.findViewButId(R.id.icon)); 
        convertView.setTag(holder); 
    } else { 
        holder = (ViewHolder) convertView.getTag(); 
    }  
    holder.text.setText(DATA[pos]); 
    holder.icon.setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2); 
    return convertView; 
} 

更新率比較如下圖:

QQ截圖20130819151124

2. 使用工作執行緒載入資料,減輕UI主執行緒負擔,使UI主執行緒只專注於UI繪製

// Using an AsyncTask to load the slow images in a background thread
new AsyncTask<ViewHolder, Void, Bitmap>() {
    private ViewHolder v;

    @Override
    protected Bitmap doInBackground(ViewHolder... params) {
        v = params[0];
        return mFakeImageLoader.getImage();
    }

    @Override
    protected void onPostExecute(Bitmap result) {
        super.onPostExecute(result);
        if (v.position == position) {
            // If this item hasn't been recycled already, hide the
            // progress and set and show the image
            v.progress.setVisibility(View.GONE);
            v.icon.setVisibility(View.VISIBLE);
            v.icon.setImageBitmap(result);
        }
    }
}.execute(holder);

3. 優化item佈局,儘量優化子view佈局不被過渡重繪,每一點子view的優化都能提高整體的效能

 參見 Android開發優化-佈局優化

相關文章