由於如今的高清圖片佔用內存大,而java
Android對單個應用所施加的內存限制,只有十幾M,如16M,這致使加載Bitmap的時候很容易出現內存溢出。android
以下報錯信息:數組
java.lang.OutOfMemoryError:bitmap size exceeds VM budget
bash
爲了解決這個問題,就出現了Bitmap的高效加載策略。markdown
其核心思想很簡單。 假設經過ImageView來顯示圖片,不少時候ImageView並無原始圖片的尺寸那麼大,這個時候把整個圖片加載進來後再設置給ImageView,顯然是沒有必要的,由於ImageView根本沒辦法顯示原始圖片,這時候能夠按必定的採樣率來縮小圖片再加載進來,這樣圖片既能在ImageVIew顯示出來,也能下降內存佔用從而必定程度上避免OOM,提升Bitmap加載時的性能。性能
BItmap在android中指的是一張圖片,經過BitmapFactory類提供的四類方法:spa
decodeFile、decodeResource、decodeStream和decodeByteArray
,分別從文件系統、資源、輸入流和字節數組中加載一個Bitmap對象,其中decodeFile和decodeResource又間接調用decodeStream方法,這四類方法最終在Android的底層實現,對應着BitmapFactory類的幾個native方法。code
上述四類方法都支持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的指數代替。
咱們須要獲取加載圖片的寬高信息,而後交給inSampleSize參數選擇縮放比縮放。那麼如何能先不加載圖片卻能獲取圖片的寬高信息,經過inJustDecodeBounds=true
,而後加載圖片就能夠實現只解析圖片的寬高信息,並不會真正的加載圖片,因此這個操做時輕量級的,當獲取了寬高信息,計算出縮放比後,而後再將inJustDecodeBounds=false,再從新加載圖片,就能夠加載縮小後的圖片。
注意:BitmapFactory獲取的圖片寬高信息和圖片的位置與程序運行的設備有關係,好比同一張圖片放在不一樣的drawable目錄下或者程序運行在不一樣屏幕密度的設備上,均可能致使BitmapFactory獲取到不一樣的結果。
BitmapFactory.Options
的inJustDecodeBounds
參數設置爲true
並加載圖片BitmapFactory.Options
中取出圖片的原始寬高信息,它們對應的outWidth
和outHeight
參數inSampleSize
BitmapFactory.Options
的inJustDecodeBounds
參數設爲false
,而後從新加載圖片。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等