2011年8月4日 星期四

讀Bitmap導致記憶體不足

做一個Android應用程式, 可以更換不同的圖片, 以選擇一幅自己要的, 採用ImageSwitch, 經歷了幾個階段
  1. 一開始, 我使用Dialog來選擇圖片, 可以總選擇了幾個以後, 就出現異常錯誤, 後來用程式碼抓了一下, 發現是記憶體不足的錯誤。

    try {
    bm = BitmapFactory.decodeFile(files[index]);
    imvPickVisual.setImageBitmap(bm);
    } catch(Exception e) {
    Log.e(TAG,e.getMessage());
    } catch(OutOfMemoryError e) {
    Log.e(TAG,e.getMessage());
    }

    原來,有catch(Exception e), 並不能捕捉出記憶體不夠的錯誤,加了 catch(OutOfMemoryError e) 後,補捉到了這個錯誤,然而,為什麼如此呢?
  2. 第一個念頭是,會不會在Dialog中實現,在複雜了,導致錯誤? 因此就改用Activity來現實,在辛苦了一下之後,Dialog沒有了,直接啟動Activity,結果還是一樣。
    接著想,是否是ImageSwitcher的問題,自己用這個元件來實現,這個元件一開始調用了makeView()函數(而且被調用了兩次), 然後圖片轉換時,就不再調用了,是否ImageSwitcher必須要配合Gallery來使用? 因此就加上Gallery好了,結果在2.2版本中,左側的元件表是有Gallery, 但是,放入layout後,系統就說,找不到這個類別(class),必須重新定義,但是改成2.3版就正常了,既然這個元件在2.2版中有定義,也就不必自己在2.2來一回。
  3. 接著想,那改成ImageView好了,反正就只有簡單的,左劃下一張,右劃上一張,如此而己。又辛苦了一下,把ImageSwitcher改成ImageView, 結果仍然相同,選了幾張以後,就Out of memory了。
  4. 再爬一下網路,發現,原來罪魁禍首是 decodeFile(), 這個函數將整個圖片抓下來,釋放沒有及時,幾張圖後,記憶體就完了。要在decode時,加上scale, 而scale最好是2的指數,運算會比較快,實際decode的圖,會是原來圖的1/scale。因此,
    1. 先讀出圖的尺寸
    2. 決定scle
    3. 依scale來decode

    public static Bitmap decodeFile(File file, int max_size) {
    Bitmap bm = null;
    try {
    //Check the image size to be decode, to decide sample size
    BitmapFactory.Options op = new BitmapFactory.Options();
    op.inJustDecodeBounds = true;
    FileInputStream isFile = new FileInputStream(file);
    BitmapFactory.decodeStream(isFile, null, op);
    isFile.close();
    int scale = 1;
    if (op.outHeight > max_size || op.outWidth > max_size) {
    scale = (int) Math.pow(2, (int) Math.round(Math.log(max_size / (double) Math.max(op.outHeight, op.outWidth)) / Math.log(0.5)));
    }

    //Decode with inSampleSize
    op = new BitmapFactory.Options();
    op.inSampleSize = scale;
    isFile = new FileInputStream(file);
    bm = BitmapFactory.decodeStream(isFile, null, op);
    isFile.close();
    } catch(Exception e) {
    Log.e(TAG, e.getMessage());
    }
    return bm;
    }

沒有留言:

張貼留言