首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android 顯示多張圖片 OOM 解決:Bitmap 采樣率與內存復用

     編輯:程式設計綜合問答

現象

循環 setImageResource 加載 4 張圖片 (720×480) 時 OOM,減為 2 張正常。AVD 內存默認較小 (如 256MB)。

根因

  • setImageResource 內部調用 BitmapFactory.decodeResource,**完整解碼原圖到內存**,每張約 720×480×4 = 1.3MB,4 張 > 5MB 加上系統開銷超過 Dalvik/ART 堆限制。
  • 無 **inBitmap 復用** (API 11-18) 或 **LruCache** (API 12+),重複解碼同一資源。

解決方案對比

推薦:接入圖片加載庫 (Glide 4.x)

// build.gradle
implementation 'com.github.bumptech.glide:glide:4.16.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'

// 使用
Glide.with(this)
     .load(R.drawable.img01) // 或 URL/File/Uri
     .override(360, 240)     // 目標尺寸,自動計算 inSampleSize
     .placeholder(R.drawable.placeholder)
     .error(R.drawable.error)
     .into(imageView);

手動優化代碼 (不引入庫)

public static Bitmap decodeSampledBitmap(Resources res, int resId, int reqW, int reqH) {
    // 1. 僅解碼邊界
    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, opts);
    
    // 2. 計算最佳 inSampleSize (2的冪次)
    opts.inSampleSize = calculateInSampleSize(opts, reqW, reqH);
    
    // 3. 真實解碼
    opts.inJustDecodeBounds = false;
    opts.inPreferredConfig = Bitmap.Config.RGB_565; // 节省50%内存
    return BitmapFactory.decodeResource(res, resId, opts);
}

static int calculateInSampleSize(BitmapFactory.Options opts, int reqW, int reqH) {
    int inSampleSize = 1;
    if (opts.outHeight > reqH || opts.outWidth > reqW) {
        int halfH = opts.outHeight / 2;
        int halfW = opts.outWidth / 2;
        while ((halfH / inSampleSize) >= reqH && (halfW / inSampleSize) >= reqW)
            inSampleSize *= 2;
    }
    return inSampleSize;
}

// 在 Activity 中使用
for (int i = 0; i < 4; i++) {
    Bitmap bmp = decodeSampledBitmap(getResources(), imagePath[i], 360, 240);
    img[i].setImageBitmap(bmp);
    // 重要:Activity 銷毀時 recycle()
    // 或維護 LruCache 復用
}

內存監控與調試

  • Android Studio Profiler → Memory 實時觀察堆變化。
  • adb shell dumpsys meminfo 包名 查看 PSS/Private Dirty。
  • 開啟 Developer Options → Show GPU Overdraw / Debug GPU Overdraw 檢測過度繪制。

總結

  1. **不要直接 setImageResource 大圖**,必須亞採樣或用庫。
  2. **生產項目直接用 Glide/Coil**,自動處理緩存、生命周期、圖片請求合併、GIF、轉換。
  3. 測試時**調大 AVD/真機內存**,或用 android:largeHeap="true" (慎用)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方案API Level核心代碼適用場景
inSampleSize 亞採樣所有opts.inSampleSize = calculateInSampleSize(opts, reqW, reqH);縮略圖、列表展示
inBitmap 復用 (舊)11-18opts.inBitmap = reusableBitmap;舊版本適配
LruCache + 異步加載12+ (推薦)Glide/Picasso/Coil 庫一行代碼生產項目標配
decodeStream 避免 Java 層拷貝所有BitmapFactory.decodeStream(is, null, opts)手動優化