2012年6月4日 星期一

[Android] Bitmap out of memory 一些解決法

使用 Bitmap 在讀取較大的原始圖片時,常會發生 Out of memory 的錯誤
即可以利用 Bitmap.Options 的參數設定來降低讀取圖片時所需要的記憶體
其中 Android Developer 官方所教導的方法是使用 isSampleSize 的方式來降低讀取圖檔時所需要的 memory

該參數大於 1 時
如 2 即表示回傳的解析度為 width /2 * height / 2 的圖檔
4 即表示回傳的解析度為 width /4 * height /4 的圖檔
依此類堆
因解析度少很多,故可以減少讀圖檔的 memory

這部份的 code 可以依自己需求修改,跟官方不太一樣
以下所計算的方式是將圖片縮到比想要的解析度大一點的最小縮圖,求在顯示時有較佳的解析度
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) 
{
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;
  
    inSampleSize = (int) Math.min(Math.ceil((float)width/(float)reqWidth),  Math.ceil((float)height/(float)reqHeight));

    return inSampleSize;
}

public static Bitmap decodeSampledBitmapFromFile(String fileName, int reqWidth, int reqHeight) 
{
    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(fileName, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(fileName, options);
}
ps: inJustDecodeBounds 的參數表示會讀取圖片的一些 info 但不會將圖檔本體讀進來
此時可以讀到圖檔的寬高並無法使用該圖檔去處理或顯示(因為沒讀進 memory)

不過竟然有這樣的參數
interface 應該有可能實現,直接讀取想要寬高的圖檔才對!?


Ref:http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

這樣的方式雖然可以大量減少 out of  memory 的問題
但還是有可能會發生
所以還是可以配合

bitmap.recycle();
System.gc();

來減少發生

更詳細與其他解法的 Ref:
http://givemepass.blogspot.tw/2011/11/blog-post_16.html
http://bluegray-javalearning.blogspot.tw/2011/07/android-out-of-memoryoom.html