Android中Bitmap壓縮策略

1、爲何BItmap須要高效加載

由於如今的高清圖片佔用內存大,而java

Android對單個應用所施加的內存限制,只有十幾M,如16M,這致使加載Bitmap的時候很容易出現內存溢出。android

以下報錯信息:數組

java.lang.OutOfMemoryError:bitmap size exceeds VM budgetbash

爲了解決這個問題,就出現了Bitmap的高效加載策略。markdown

其核心思想很簡單。 假設經過ImageView來顯示圖片,不少時候ImageView並無原始圖片的尺寸那麼大,這個時候把整個圖片加載進來後再設置給ImageView,顯然是沒有必要的,由於ImageView根本沒辦法顯示原始圖片,這時候能夠按必定的採樣率來縮小圖片再加載進來,這樣圖片既能在ImageVIew顯示出來,也能下降內存佔用從而必定程度上避免OOM,提升Bitmap加載時的性能。性能


2、Bitmap高效加載的具體方式

一、加載Bitmap的方式

BItmap在android中指的是一張圖片,經過BitmapFactory類提供的四類方法:spa

decodeFile、decodeResource、decodeStream和decodeByteArray,分別從文件系統、資源、輸入流和字節數組中加載一個Bitmap對象,其中decodeFile和decodeResource又間接調用decodeStream方法,這四類方法最終在Android的底層實現,對應着BitmapFactory類的幾個native方法code


二、BitmapFatory.Options的參數

  • inSampleSize參數

上述四類方法都支持BitmapFactory.Options參數,而Bitmap是按必定採樣率進行縮放,即經過BitmapFactory.Options參數實現,主要用到了inSampleSize參數,即採樣率。經過對inSampleSize的設置,對圖片的像素的高和寬進行縮放。orm


當inSampleSize=1,即採樣後的圖片大小爲原始大小,對象

如inSamoleSize < 1,也按照1來計算

若inSampleSize > 1,即採樣後的圖片將縮小,縮小比例1/(inSampleSize的二次方)


注意:官方文檔指出:inSampleSize的取值應該老是2的指數,如1,2,4,8等,若是外界傳入的inSampleSize的孩子不爲2的指數,那麼系統會向下取整並選擇一個最接近2的指數代替。


  • inJustDecodeBounds參數

咱們須要獲取加載圖片的寬高信息,而後交給inSampleSize參數選擇縮放比縮放。那麼如何能先不加載圖片卻能獲取圖片的寬高信息,經過inJustDecodeBounds=true,而後加載圖片就能夠實現只解析圖片的寬高信息,並不會真正的加載圖片,因此這個操做時輕量級的,當獲取了寬高信息,計算出縮放比後,而後再將inJustDecodeBounds=false,再從新加載圖片,就能夠加載縮小後的圖片。


注意:BitmapFactory獲取的圖片寬高信息和圖片的位置程序運行的設備有關係,好比同一張圖片放在不一樣的drawable目錄下或者程序運行在不一樣屏幕密度的設備上,均可能致使BitmapFactory獲取到不一樣的結果。


三、高效加載Bitmap的流程

  • BitmapFactory.OptionsinJustDecodeBounds參數設置爲true並加載圖片
  • BitmapFactory.Options中取出圖片的原始寬高信息,它們對應的outWidthoutHeight參數
  • 根據採樣率的規則並結合目標View的所需大小計算出採樣率inSampleSize
  • BitmapFactory.OptionsinJustDecodeBounds參數設爲false,而後從新加載圖片


3、Bitmap高效加載的代碼實現

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, 
              int reqWidth, int reqHeight){
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    //加載圖片
    BitmapFactory.decodeResource(res,resId,options);
    //計算縮放比
    options.inSampleSize = calculateInSampleSize(options,reqHeight,reqWidth);
    //從新加載圖片
    options.inJustDecodeBounds =false;
    return BitmapFactory.decodeResource(res,resId,options);
}

private static int calculateInSampleSize(BitmapFactory.Options options, 
                int reqHeight, int reqWidth) {
    int height = options.outHeight;
    int width = options.outWidth;
    int inSampleSize = 1;
    if(height>reqHeight||width>reqWidth){
        int halfHeight = height/2;
        int halfWidth = width/2;
        //計算縮放比,是2的指數
        while((halfHeight/inSampleSize) >= reqHeight&&
                   (halfWidth/inSampleSize) >= reqWidth){
            inSampleSize*=2;
        }
    }
    return inSampleSize;
}複製代碼

這個時候能夠經過以下方法高效加載圖片:

mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(),R.mipmap.ic_launcher,100,100));複製代碼

除了BItmapFactory的decodeResource方法,其餘方法也能夠,如decodeFile、decodeByteArray等

相關文章
相關標籤/搜索