Android Bitmap那些事之如何優化內存

前言:”安得廣夏千萬間,大庇天下寒士俱歡顏“——杜甫。在帝都住的朋友們都可能會遇到租房子困難的問題(土豪請無視),找房子真是力氣活,還耗費時間,佔用我寶貴的寫博客時間,沒辦法,誰讓咱沒錢還想住的好點,努力努力掙錢!!!以上發點牢騷,現在進入正題。上一篇博客《Bitmap那些事之內存佔用計算和加載注意事項》,寫了Bitmap基礎知識和使用Bitmap需要知道的注意事項,這一片博客我會寫在Android應用中Bitmap的創建和加載。

 

1、BitmapFactory使用:

 

說到圖片的加載就必須說BitmapFactory,看名字就知道他的作用了,就是一個生產Bitmap的工廠,下圖是它的一些工廠方法:

 

 

spacer.gif

從上圖可以看到BitmapFactory可以使用存儲Bitmap數據的數組,Bitmap的資源ID,Bitmap文件等做爲數據源來創建Bitmap對象,具體情況看你程序中提供的數據源是哪一種。這些方法中對每一種數據源都提供了兩個方法,這裏需要注意一下BitmapFacotry.Options參數,它是BitmapFactory的內部類,有一些成員變量含義需要記一下,下面就來說說。

 

2、BitmapFacotry.Options的inJustDecodeBounds 參數使用:

爲了節省內存,很多情況下原圖片都要經過縮放處理,根據控件的尺寸來處理成對應尺寸的圖片,這時使用BitmapFactory創建Bitmap,很多情況下都會使用下面的代碼:

複製代碼

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds =true;
BitmapFactory.decodeResource(getResources(), R.id.myp_w_picpath, options);int p_w_picpathHeight = options.outHeight;int p_w_picpathWidth = options.outWidth;
String p_w_picpathType = options.outMimeType;

複製代碼

注意上面中的options.inJustDecodeBounds =true的inJustDecodeBounds參數,爲了避免我翻譯的不準確我這裏先貼出來google的原文: If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels。用我的話來說就是在decode的時候不給這個bitmap的像素區分配內存,除了這個區別Bitmap的其他信息你都能獲取到。這樣就有很大的意義,你既沒有消耗內存又拿到了圖片的信息,爲你下一步圖片處理提供幫助。

 

3、BitmapFacotry.Options的inSampleSize參數使用:

 

上一步你已經獲取到圖片的原始尺寸了,下一步就是要把原圖縮放到你需要的大小,可以通過inSampleSize參數來設置,google原文的解釋是:If set to a value > 1, requests the decoder to subsample the original p_w_picpath, returning a smaller p_w_picpath to save memory. The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns an p_w_picpath that is 1/4 the width/height of the original, and 1/16 the number of pixels. Any value <= 1 is treated the same as 1. Note: the decoder will try to fulfill this request, but the resulting bitmap may have different dimensions that precisely what has been requested. Also, powers of 2 are often faster/easier for the decoder to honor.(不管你看不看英文文檔我還是要把google原文貼出來,我英文比較爛,翻譯的不一定準確),大概意思就是說這個參數可以調節你在decode原圖時所需要的內存,有點像採樣率,會丟掉一些像素,值是大於1的數,爲2的冪時更利於運算。舉個例子:當 inSampleSize == 4 時會返回一個尺寸(長和寬)是原始尺寸1/4,像素是原來1/16的圖片。這個值怎麼計算呢?

複製代碼

public static int calculateInSampleSize(
            BitmapFactory.Options options,int reqWidth,int reqHeight){    // Raw height and width of p_w_picpath
    finalint height = options.outHeight;
    finalint width = options.outWidth;    int inSampleSize =1;    if(height > reqHeight || width > reqWidth){

        finalint halfHeight = height /2;
        finalint halfWidth = width /2;        // Calculate the largest inSampleSize value that is a power of 2 and keeps both        // height and width larger than the requested height and width.
        while((halfHeight / inSampleSize)> reqHeight                &&(halfWidth / inSampleSize)> reqWidth){
            inSampleSize *=2;
        }
    }    return inSampleSize;
}

複製代碼

在decode的時候先設置options.inJustDecodeBounds =true,獲取到圖片參數後再設置爲false,這就是decode時的技巧,下面就把完整代碼貼出來,可以作爲工具方法來使用:

複製代碼

public static Bitmap decodeSampledBitmapFromResource(Resources res,int resId,        int reqWidth,int reqHeight){    // First decode with inJustDecodeBounds=true to check dimensions
    finalBitmapFactory.Options options =newBitmapFactory.Options();
    options.inJustDecodeBounds =true;
    BitmapFactory.decodeResource(res, resId, options);    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds =false;
    returnBitmapFactory.decodeResource(res, resId, options);
}

複製代碼

上面的方法來自於google官網,沒必要進行修改,這就是程序員的拿來主義吧,關鍵在於要知道爲什麼這麼寫。下面是我自己寫的一個方法可以直接拿來當工具用。

複製代碼

    /**
     * 對圖片進行壓縮,主要是爲了解決控件顯示過大圖片佔用內存造成OOM問題,一般壓縮後的圖片大小應該和用來展示它的控件大小相近.
     *
     * @param context 上下文
     * @param resId 圖片資源Id
     * @param reqWidth 期望壓縮的寬度
     * @param reqHeight 期望壓縮的高度
     * @return 壓縮後的圖片     */
    public static Bitmap compressBitmapFromResourse(Context context, int resId, int reqWidth, int reqHeight) {        final BitmapFactory.Options options = new BitmapFactory.Options();        /*
         * 第一次解析時,inJustDecodeBounds設置爲true,
         * 禁止爲bitmap分配內存,雖然bitmap返回值爲空,但可以獲取圖片大小         */
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(context.getResources(), resId, options);        final int height = options.outHeight;        final int width = options.outWidth;        int inSampleSize = 1;        if (height > reqHeight || width > reqWidth) {            final int heightRatio = Math.round((float) height / (float) reqHeight);            final int widthRatio = Math.round((float) width / (float) reqWidth);
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        options.inSampleSize = inSampleSize;        // 使用計算得到的inSampleSize值再次解析圖片
        options.inJustDecodeBounds = false;        return BitmapFactory.decodeResource(context.getResources(), resId, options);
    }

複製代碼

 

以上就是Bitmap在Android中加載到內存中的一些小技巧,大家是不是以後就能很好的應用起來,避免因爲加載圖片引起OOM這樣的問題呢?如果您有更好更棒的方法可以給我留言或者添加我的微信公衆號:coder_online。大家共同學習,共同進步,賺錢不再爲房子發愁。你可以方便的掃描下面的二維碼進行添加:

                                                            

摘自:http://www.cnblogs.com/2010wuhao/p/4443413.html


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