Bitmapfactory Out of Memory

很多時候,在我們使用BitmapFactory 會產生out of memory的錯誤。因為記憶體對android系統是很寶貴的。所以每一個程式都會限制在一定大小的記憶體裡,只要超過了,系統就會顯示out of memory。通常都會發生在載入圖片的時候。

如果一張2592*1936像素大小的圖片,每一個像素又使用ARGB_8888,那麼他的大小就是19M左右(2592*1936*4 bytes)。這跟圖片格式無關,當程式載入圖片到記憶體中時,就是要恢復成Bitmap去對應螢幕上的每一個像素。所以,如果我們要載入照片,因為現在的照片格式都很大,我們不可能一一去了解照片的格式和大小。就需要用到BitmapFactory.Options的功能。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
 
這一段程式的內容是利用options.inJustDecodebounds設定為true。如此
 
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
 
將會返回一個null值,也就是說圖片將不會被載入記憶體中。而只是讀入圖片的基本資料,如長寬和檔案的類形。等讀入圖形的基本資料後,先預先做處理,再讀入記憶體中,就不容易出現out of memory了。

我們來看看deveolper上的例子。

public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
        if (width > height) {
            inSampleSize = Math.round((float)height / (float)reqHeight);
        } else {
            inSampleSize = Math.round((float)width / (float)reqWidth);
        }
    }
    return inSampleSize;
}
 
忘了說明option中有一個參數 inSampleSize。這是一個整數。如果為2,就是載入圖片1/2的解析度。如果是3就是載入1/3圖片的解析度。這樣大大的縮小了圖片在記憶體中的大小。很多時候,因為手機解析度的不同,載入一張完整的,不破壞的圖片,不是那麼有意義。


calculateInSampleSize這個函式就是要從預先得到的BitmapFactory.Options來計算inSampleSize。
 
用法如下
 

  
  final BitmapFactory.Options options = new BitmapFactory.Options();
   //先將inJustDecodeBounds設成true,不讓圖片載入記憶體。
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // 代入calculateInSampleSize計算inSampleSize的大小。
 
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // 將inJustDecodeBounds設成false,讓圖片載入記憶體。
    options.inJustDecodeBounds = false;
    Bitmap bitmapWeGot=BitmapFactory.decodeResource(res, resId, options);
 
 
如此載入記憶體中的bitmapWeGot就會是一個有效利用記憶體的圖片了。 

留言

這個網誌中的熱門文章

python 找圖自動點擊

Python pyserial 抓取系統內的 COM PORT

VBA EXCEL 工作表變化 馬上執行 的作法 Worksheet_Change