最近做的項目裡,需要在首頁面加載很多圖檔。那麼就嘗嘗出現OOM,嘗試了多種方法,最後找到一種很不錯的辦法,極大的節省了記憶體空間,原先程式運作時的記憶體占有量大約在120-200左右,又時甚至能達到醉人的250直接OOM掉。修改過後,長期穩定在60-100M之間。是以說優化了接近50%。那麼現在我們就來看看,我是怎麼做的~~
【一】使用Drawable代替bitmap
經過實際測試發現,Drawable在加載圖檔的性能上和占用記憶體上都遠小于bitmap。(實驗證明,加載同樣的1000張圖檔,drawable可以快速的加載完1000張圖檔,而bitmap僅僅加載到第8張就OOM了。。。)本人才疏學淺不止其中奧義,也不知道為什麼大家都愛用bitmap,也希望有識之士能夠告知我一下原因。
詳見:http://blog.csdn.net/zhu071011/article/details/48310597
【二】使用decodeStream杜絕decodeResource
同樣是經過大量實幹中得出的經驗。decodeStream的加載方式是調用了非java層面的代碼進行操作的,是以效率很高。經過試驗,用bitmap去加載1000張圖檔,使用decodeResource的隻能加載到第8張,使用decodeStream的可以加載到566張,可見其效率提升的多麼顯著。
示例:
public static Bitmap readBitMap(Context context, int resId) {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Bitmap.Config.ARGB_4444;
opt.inPurgeable = true;
opt.inInputShareable = true;
// 擷取資源圖檔
InputStream is = context.getResources().openRawResource(resId);
Bitmap bitmap = BitmapFactory.decodeStream(is, null, opt);
try {
if(is != null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
【三】巧用BitmapFactroy.Options進行圖像高效壓縮
網上鋪天蓋地的都是推薦使用simplesize來進行圖像壓縮,然而,我卻發現一種更節省記憶體的方法。依然是使用BitmapFactroy.Options,通過設定圖檔的顯示密度來壓縮圖檔,進而達到減小記憶體占用量的目的。
讓我們先看一段示例代碼:
public Drawable loadImageFromUrl(int id) {
if(id<0 || id==0) {
return null;
}
int targetdensity = mContext.getResources().getDisplayMetrics().densityDpi;
BitmapFactory.Options opt = new Options();
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inScaled=true;
opt.inTargetDensity=targetdensity;
//inDensity bigger,image memory size smaller.now set to density=screendensityDpi*density
//eg:density = (sw)320*(dpi)2
opt.inDensity = (int)(targetdensity*mContext.getResources().getDisplayMetrics().density);
opt.inJustDecodeBounds = false;
InputStream is = null;
Drawable drawable = null;
try {
is = mContext.getResources().openRawResource(id);
/*Bitmap bitmap = BitmapFactory.decodeStream(is, null, opt);
drawable = new BitmapDrawable(mContext.getResources(), bitmap);*/
drawable = Drawable.createFromResourceStream(mContext.getResources(),null,is,null,opt);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try{
is.close();
} catch (Exception e) {
}
}
}
return drawable;
}
這段代碼可以有效的降低圖檔資源的記憶體占用量,關鍵原因就是inDensity的設定。這個選項我還沒有摸透他具體的意義。但是就查找到的資料來看,他是定義你要現實的圖檔的密度的。然而與我想象中完全相反的是,這個數值設定的越大,圖檔的壓縮了就越高。一般我喜歡設定成手機螢幕的density乘以手機螢幕密度。如擷取到手機的density是320,手機的像素密度是2,那麼inDensity就設定為640。
是以,綜上所述:
節省記憶體的加載圖檔方式為:
Drawable+Stream方式加載+壓縮,如上面代碼所示。
後期我如果找到了原理,再更新。