概述
現在的圖片是動輒幾M到幾十M,而系統分配給應用的內存有限,如果直接將原圖載入內存,這會導致Bitmap加載的時候很容易出現內存溢出(OOM)。 Bitmap高效加載的策略:根據圖片展示控件的尺寸,將圖片以一定的採樣率進行縮放後再加載。這樣就能降低內存佔用,從而在一定程度上避免OOM,並提高Bitmap加載時的性能。
Bitmap的加載方式
BitmapFactory
提供了四類方法來加載Bitmap: decodeFile:從文件加載Bitmap decodeResource:從資源中加載Bitmap decodeStream:從輸入流中加載Bitmap decodeByteArray:從字節數組中加載Bitmap 這四類方法都分別有一個帶BitmapFactory.Options
參數的重載方法,通過對這個參數的配置從而達到高效加載Bitmap。
BitmapFactory.Options的屬性
inSampleSize
inSampleSize
:即採樣率,通過對其設置,實現圖片的寬和高縮放。 當inSampleSize=1:採樣後的圖片大小爲圖片的原始大小。 當inSameleSize<1:按=1計算 當inSampleSize>1:採樣後的圖片將會縮小,縮放比例爲1 / (inSampleSize的2次方)。 inSampleSize取值:inSampleSize的取值應該總是2的指數,如1,2,4,8等,如果傳入的inSampleSize的值不爲2的指數,那麼系統會向下取整並選擇一個最接近2的指數來代替。比如3,系統會選擇2來代替。
示例:
一張2048x1536像素的圖片,採用ARGB_8888進行存儲,那麼內存大小2048 x 1536 x 4 = 12M,如果inSampleSize = 4,那麼採樣後的圖片內存大小:512 x 384 x 4 = 0.75M
inJustDecodeBounds
在計算圖片縮放比的時候,我們需要先獲取到圖片的原始寬高,通過設置
inJustDecodeBounds=true
,就可以在不將圖片加載進內存的情況下,解析出圖片的寬高信息。計算出縮放比後,再設置inJustDecodeBounds=false
,根據縮放比加載縮放後的圖片。
高效加載Bitmap流程
- 將BitmapFactory.Options的
inJustDecodeBounds
參數設爲true
並加載圖片。 - 從BitmapFactory.Options中取出圖片的原始寬高信息,它們對應
outWidth
和outHeight
參數。 - 根據採樣率的規則並結合目標View的所需大小計算出採樣率
inSampleSize
。 - 將BitmapFactory.Options的
inJustDecodeBounds
參數設爲false
,然後重新加載圖片。
代碼實現:
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // 首次加載獲取圖片的原始寬高 final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // 計算縮放比 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 重新加載圖片 options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); } public static int calculateInSampleSize (BitmapFactory.Options options, int reqWidth, int reqHeight) { // 圖片的原始寬高 final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // 計算縮放比,是2的指數, // 取寬高的最小縮放比,如寬的縮放比爲2,高的縮放比爲4,那麼取2作爲整體的縮放比 while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
使用:
mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
參考鏈接
- https://www.jianshu.com/p/5f02db4a225d
- https://developer.android.google.cn/topic/performance/graphics/load-bitmap