圖片分辨率往往遠超螢幕顯示需求(如相機拍攝 4000×3000,手機螢幕 1080×1920)。直接載入原圖會佔用大量記憶體,導致 OutOfMemoryError,且影響滑動流暢度。解決方案:載入縮放後的版本,尺寸匹配 UI 控件大小。
inJustDecodeBounds = true:不分配記憶體,僅解碼邊界,獲取 outWidth, outHeight, outMimeType。inSampleSize:縮放比例(2 的冪),如設為 4,寬高各縮小 4 倍,記憶體佔用約 1/16。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;
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
原理:取最大的 2 的冪,使縮放後寬高仍 ≥ 目標尺寸。解碼器最終會向下取最接近的 2 的冪。
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
// 1. 預檢尺寸
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// 2. 計算縮放比
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// 3. 真正解碼
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
mImageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100)
);
同理可用 decodeFile, decodeByteArray, decodeStream 等方法,只需替換對應的 decode* 呼叫。
inJustDecodeBounds=true 獲取原圖尺寸。inSampleSize(2 的冪)。inJustDecodeBounds=false 並重新解碼獲取縮放後 Bitmap。此技術是 Android 圖片載入優化的基石,掌握它能有效避免 OOM 並提升滾動性能。