天天看點

Android圖檔加載方案——如何保證圖檔清晰度同時,最大限度節省記憶體使用量

最近做的項目裡,需要在首頁面加載很多圖檔。那麼就嘗嘗出現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方式加載+壓縮,如上面代碼所示。

後期我如果找到了原理,再更新。