2013年8月19日 星期一

Android Bitmap OOM系列(2):利用convertView/holder 改良GridView

撰寫於2012年09月29日| 沒有評論
      在上一篇日誌《Android Bitmap OOM系列(1):GridView》中,我們已經成功的讓GridView跑起來了,但是這是最最原始的實現方式之一,它的效率也是非常之低(我們的圖片都是來自於項目中,而且都是微小圖片,所以感受不到),一旦圖片的分辨率比較大,而且圖片數量多的話,應用很容易因為內存爆掉而導致FC(Force close)。這是因為我們在getView方法中始終是new一個新的View出來,如此一來,一旦有100張圖,我們就要new 100次,同時當我們滾動GridView的時候,即使是顯示在界面上過的View也會重新new一次。而同時Dalvik虛擬機又未能及時回收已不用的內存,當到達極限時,內存也就理所當然地爆掉了。
      在寫getView這個方法中的代碼時,我們已經發現,getView有一個參數View(參數名為convertView),在android的ListView、Gridview中,convertView是一個很有用,而且很酷的參數。根據官方文檔的解釋,它是用來在可能的情況下重用舊的視圖的。在使用之前,我們應該先檢查這個view不是空的而且是一個適當的類型。所以呢,我們現在就來把getView給改寫一下。改寫後的代碼如下:
View view = null ; 
if  ( convertView ==  null )  { 
 view = mInflater . inflate ( R . layout . gridview ,  null ); 
        ImageView imageView =  ( ImageView ) convertView . findViewById ( R . id . image ); 
 imageView . setImageBitmap ( bitmapList . get ( position )); 
} else { 
        view = convertView
 } 
return view ;
    首先我們判斷convertView是否為空,當為空時,就按照原來的邏輯去xml中尋找控件並實例化出來,然後把BItmap設置進ImageView,如果不為空,就直接將convertView賦給view。
    這次的改寫就這麼簡單,當然這個還是簡單的形式,因為我們現在只有一個ImageView而已,如果在項目中我們GridView的每一個View都是由多個控件組成(比如一個ImageView和一個TextView),那麼我們還需要建一個holder來儲存。首先我們需要建一個holder類(我比較喜歡直接寫在adapter裡作為內部類使用),它只包含2個成員變量
public  class  Holder { 
           public  TextView text ; 
           public  ImageView image ; 
}
然後在getView中使用這個holder,首先我們先實例化Holder為null,然後如同上面那樣判斷convertView是否為空,並進行相應的實例化操作。所不同的是,這裡我們不再需要new 一個ImageView出來了,我們直接把xml中讀出來的ImageView賦值給Holder的成員變量image,TextView也一樣。然後分別給他們設ImageBitamp和Text,之後把Holder設置到convertView裡面去。當convertView不為空的時候,則從convertView中取出相應Holder的視圖出來。
View view = null ; 
Holder holder = null ; 
if  ( convertView ==  null )  { 
 view = mInflater . inflate ( R . layout . gridview ,  null ); 
        holder =  new  Holder (); 
        holder . image =  ( ImageView ) convertView . findViewById ( R . id . image ); 
 holder . image . setImageBitmap ( bitmapList . get ( position )); 
        convertVIew . setTag ( holder ); 
} else { 
        view = convertView . getTag (); 
} 
return view ;
原創文章,轉載請註明:轉載自網憩閣

Google的教學:


getView

static class ViewHolder { 
TextView text; 
ImageView icon; 
}


------------------------------------------------
ViewHolder holder; 

 if (convertView == null) { 
 convertView = mInflater.inflate(R.layout.list_item_icon_text, 
  parent, false);
 holder = new ViewHolder(); 
  holder.text = (TextView) convertView.findViewById(R.id.text); 
  holder.icon = (ImageView) convertView.findViewById(R.id.icon); 

  convertView.setTag(holder); 
  } else { 
  holder = (ViewHolder) convertView.getTag(); 
  } 

  holder.text.setText(DATA[position]); 
  holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2); 

 return convertView; 
-----------------------------------------------------------


public class MyBaseAdapter extends BaseAdapter {

private Context myContext;

MyBaseAdapter(Context c) {
myContext = c;
}
public class ViewHolder { 
TextView text; 
ImageView icon; 
}
@Override
public int getCount() {
return MyAppList.size();
}

@Override
public Object getItem(int position) {
return MyAppList.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

/*View MyView = convertView;

if (convertView == null) {

MyView = new View(myContext);
MyView.setLayoutParams(new GridView.LayoutParams(85, 85));
// MyView.setScaleType(View.ScaleType.CENTER_CROP);
MyView.setPadding(8, 8, 8, 8);
} else {
MyView = (View) convertView;
}


LayoutInflater li = getLayoutInflater();
MyView = li.inflate(R.layout.grid_item, null);

// Add The Text!!!
TextView tv = (TextView) MyView.findViewById(R.id.tv);
tv.setText(MyAppList.get(position));

// Add The Image!!!

ImageView iv = (ImageView) MyView.findViewById(R.id.imageView1);
iv.setScaleType(ImageView.ScaleType.CENTER_CROP);
iv.setImageBitmap(getThumbnail("icon " + MyAppList.get(position)
+ ".png", getBaseContext()));

return MyView;*/

ViewHolder holder; 
LayoutInflater li = getLayoutInflater();
if (convertView == null) { 
convertView = li.inflate(R.layout.grid_item, 
 parent, false);
holder = new ViewHolder(); 
 holder.text = (TextView) convertView.findViewById(R.id.tv); 
 holder.icon = (ImageView) convertView.findViewById(R.id.imageView1); 
 
 convertView.setTag(holder); 
 } else { 
 holder = (ViewHolder) convertView.getTag(); 
 } 
 
 holder.text.setText(MyAppList.get(position)); 
 holder.icon.setImageBitmap(getThumbnail("icon " + MyAppList.get(position)
+ ".png", getBaseContext())); 
 
return convertView; 

}

}

"不再" Force close的 gridview
忽略一些東西, 能換來一些東西

沒有留言:

張貼留言

Related Posts Plugin for WordPress, Blogger...