android_ListView優化

ListView 優化
ListView的顯示機制:
listview會先通過onMeasure()方法計算出一個手機屏幕能展示多少個item
假如你有1000條數據,但是屏幕只能顯示10條,那麼當你第一次加載顯示的時候,會先創建10個View(調用10次getView方法),1-10,當你拖動Listview,使1隱藏而11顯示的時候,系統會自動把填充1的View傳遞過來
當我們固定listview的高度時(fill_parent或直接固定高度),那麼listview很容易就能計算(onMeasure方法)出容器內可以顯示多少行。但如果我們使用了“wrap_content”,只有在屏幕內控件完全加載後才知道到底能顯示多少行數據時,ListView自身便會做一些嘗試性計算。


ListView優化方式:
1.1 內存空間優化(ConvertView)
優化原理:重用緩存convertView傳遞給getView()方法來避免填充不必要的視圖
Q:爲什麼要convertView複用?
ListView中的每一個Item顯示都需要Adapter調用一次getView的方法,這個方法會傳入一個convertView的參數,返回的View就是這個Item顯示的View。
如果當Item的數量足夠大,再爲每一個Item都創建一個View對象,必將佔用很多內存,創建View對象(mInflater.inflate(R.layout.lv_item, null);從xml中生成View,這是屬於IO操作)也是耗時操作,所以必將影響性能。Android提供了一個叫做Recycler(反覆循環器)的構件,就是當ListView的Item從上方滾出屏幕視角之外,對應Item的View會被緩存到Recycler中,相應的會從下方生成一個Item,而此時調用的getView中的convertView參數就是滾出屏幕的Item的View,所以說如果能重用這個convertView,就會大大改善性能。


&convertView複用使用代碼說明:
View view = null;
if(convertView == null){
LayoutInflater inflater = LayoutInflater.from(context);
view = inflater.inflate(R.layout.items, null);
}else{
//如果convertView不爲空,說明該view之前加載進來過,所以直接將其賦 給view,即反覆使用,避免再創建新的view浪費資源
view = convertView;
}
TextView tv = (TextView) view.findViewById(R.id.textView1);
tv.setText(getList().get(position));
System.out.println("position-->" + position);
return view;

簡單的寫就是:
if (convertView==null ) {
convertView=LayoutInflater.from(context).inflate(layout, null);
//其他代碼
}

1.2 運行時間優化(ViewHolder)
優化原理:使用ViewHolder模式來避免沒有必要的調用findViewById():因爲太多的findViewById也會影響性能

I.寫一個ViewHolder類
static class ViewHolder {
TextView tv;
ImageView iv;
}
II.使用ViewHolder
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
LayoutInflater mLayoutInflater = LayoutInflater.from(context);
convertView = mLayoutInflater.inflate(layout, null);
viewHolder = new ViewHolder();
convertView.setTag(viewHolder);
viewHolder.tv = (TextView) convertView.findViewById(R.id.tv);
viewHolder.iv = (ImageView) convertView.findViewById(R.id.iv);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
return convertView; }

1.3異步加載圖片出錯
爲了防止ListView異步加載圖片錯位、重複、閃爍等情況,我們需要給ImageView設置一個Tag,這個Tag中設置的是圖片的url,在異步加載完成時我們可以比較下圖片的url與當前行Item的標識是否一致,一致則顯示,否則不做處理即可。方法步驟:
1.給當前ImageView對象設置標識
viewholder.iv.setTag(img_url);

2.給當前ImageView設置一個默認的值(因爲控件是複用的, 用完之後其中的值還存在,所以需要清洗下,這裏可以給隨意給一張默認的圖片)
viewholder.iv.setImageResource(R.drawable.ic_launcher);

3.在異步類裏面判斷tag值和圖片地址是否相等,若相等,則說明該控件在當前的位置所需要展示的圖片 是對的,就可以直接展示出來.這裏有兩種方法實現:
第一種在異步線程onPostExecute()方法裏設置:
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);

// 防止圖片錯位,判斷下tag值和圖片地址是否相等
if (result != null && img_url.equals(iv.getTag())) {
// 設置圖片
iv.setImageBitmap(result);
}
}

第二種在:在繼承BaseAdapter類getView()方法進行設置:
//設置標識
viewHolder.iv.setTag(url);
//設置默認圖片佔位
viewHolder.iv.setImageResource(R.drawable.ic_launcher);
MyBitmapTask task=new MyBitmapTask();
task.execute(url);
viewHolder.tv.setText(str);
task.setBitmapInterface(new MyBitmapInterface() {
@Override
public void getBitmap(Bitmap bmp) {
if (bmp!=null&& viewHolder.iv.getTag().equals(url)) {
viewHolder.iv.setImageBitmap(bmp);
}
}
});

--------------------------------------------------------------------------------------------------------


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章