Android對單個應用有內存限制,比如16MB,這導致加載Bitmap時很容易出現內存溢出:
java.lang.OutofMemoryError:bitmap size exceeds VM budget
因此我們需要考慮如何高效加載bitmap,避免發生內存溢出。
首先回顧一下如何加載一個bitmap:
BitmapFactory提供了四類方法:decodeFile、decodeResource、decodeStream、decodeByteArray,其中decodeFile、decodeResource間接調用了decodeStream方法,這四類最終都是在android底層實現的。
那麼如何高效地加載bitmap呢?
採用BitmapFactory.Options來縮放圖片。以ImageView爲例,很多時候ImageView沒有原始圖片那麼大,將圖片整個加載進來再設給ImageView顯得沒有必要,因爲ImageView沒有辦法顯示原始的圖片。這時就可以通過BitmapFactory.Options按一定的採樣率來加載縮小後的圖片,這樣就會降低內存佔用從而在一定程度上避免OOM,提高了bitmap加載時的性能。
通過BitmapFactory.Options縮放圖片,主要用到它的inSampleSize參數,即採樣率。當inSampleSize爲1時,採樣後的圖片大小爲圖片的原始大小;當inSampleSize大於1時,比如2,那麼採樣後圖片的寬高均爲原圖大小的1/2,像素數爲原圖的1/4,其佔有的內存大小也爲原圖的1/4。inSampleSize必須大於1纔會有效果,並建議取值爲2的指數,比如1、2、4、8、16。
獲取並改變採樣率的方法:
1.將BitmapFactory.Options的inJustDecodeBounds參數設爲true,設置完以後,BitmapFactory在加載bitmap時就不會真正的去加載,只是去獲取圖片原始的寬高信息,這個操作是輕量級的。
2.通過BitmapFactory加載bitmap,這樣圖片原始的寬高信息就會存儲在Options裏面了。
3.根據圖片原始的寬高、ImageView的寬高(你需要的寬高)來計算合適的inSampleSize並賦給Options.inSampleSize。
4.將BitmapFactory.Options的inJustDecodeBounds參數設回false,重新加載bitmap。
代碼實現:
public static Bitmap decodeBitmap(Resources res, int resId, int reqWidth, int reqHeight){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
//這裏必須採用傳入options的方法
BitmapFactory.decodeResource(res, resId, options);
int height = options.outHeight;
int width = options.outWidth;
int sampleSize = 1;
while(height > reqHeight || width > reqWidth){
sampleSize *= 2;
height /= 2;
width /= 2;
}
options.inSampleSize = sampleSize;
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}