1. 程式人生 > >Android BitmapFactory.decodeStream方法OutOfMemoryError 解決方法

Android BitmapFactory.decodeStream方法OutOfMemoryError 解決方法

我的Android App在執行下面程式碼時出現了OutOfMemoryError異常

image =BitmapFactory.decodeStream(assetManager.open(imgFilename));

App執行到這一步就會出現OOM異常,異常資訊如下:

(...)08-0521:22:12.443: I/dalvikvm-heap(2319):Clamp target GC heap from25.056MB to 24.000MB08-0521:22:12.443: D/dalvikvm(2319): GC_FOR_MALLOC freed <1K,50% free 2709K/5379K
, external 18296K/19336K, paused 58ms08-0521:22:14.513: D/dalvikvm(2319): GC_EXTERNAL_ALLOC freed <1K,50% free 2709K/5379K, external 18296K/19336K, paused 101ms08-0521:22:14.903: I/dalvikvm-heap(2319):Clamp target GC heap from25.073MB to 24.000MB08-0521:22:14.903: D/dalvikvm(2319): GC_FOR_MALLOC freed 0K,50% free 2709K/5379K
, external 18312K/19336K, paused 53ms08-0521:22:22.843: D/ddm-heap(2319):Heap GC request 08-0521:22:22.963: I/dalvikvm-heap(2319):Clamp target GC heap from25.073MB to 24.000MB08-0521:22:22.963: D/dalvikvm(2319): threadid=1: still suspended after undo (sc=1 dc=1)08-0521:22:22.963: D/dalvikvm(2319): GC_EXPLICIT freed
1K,50% free 2710K/5379K, external 18312K/19336K, paused 116ms

通過DDMS可以看到當時記憶體堆的使用情況

  • Heap Size:  5.254 MB
  • Allocated:  2.647 MB
  • Free:   2.607 MB
  • %Used:  50.38%
  • #Objects    49,028

只要指定到這一行就會出現OutOfMemoryError異常

08-0521:26:04.783: D/dalvikvm(2319): GC_EXTERNAL_ALLOC freed <1K,50% free 2710K/5379K, external 18312K/19336K, paused 57ms08-0521:26:05.023: E/dalvikvm-heap(2319):2097152-byte external allocation too large forthis process.08-0521:26:05.163: I/dalvikvm-heap(2319):Clamp target GC heap from25.073MB to 24.000MB08-0521:26:05.163: E/GraphicsJNI(2319): VM won't let us allocate 2097152 bytes
08-05 21:26:05.163: D/dalvikvm(2319): GC_FOR_MALLOC freed 0K, 50% free 2710K/5379K, external 18312K/19336K, paused 30ms
08-05 21:26:05.283: D/skia(2319): --- decoder->decode returned false

在windows中可以看到圖片檔案的大小是小於400K的,而BitmapFactory.decodeStream()方法卻要試圖分配2M的記憶體。

出現這個異常是因為Android類庫在處理圖片載入時不是很智慧,我們還需要做一些額外的工作。

我測試發現,Drawable.createFromStream方法要比BitmapFactory.decodeStream方法佔用更多的記憶體。

你可以通過修改圖片的顏色模式(Color schema)來減少建立圖片使用的記憶體量

BitmapFactory.Options options =newBitmapFactory.Options();
options.inPreferredConfig =Config.RGB_565;Bitmap bitmap =BitmapFactory.decodeStream(stream,null, options);

你也可以通過載入一個縮放之後的圖片,來減少建立圖片時的記憶體分配量,但是需要注意圖片縮放後可能會損失質量

BitmapFactory.Options options =newBitmapFactory.Options();
options.inSampleSize =2;Bitmap bitmap =BitmapFactory.decodeStream(stream,null, options);
BitmapFactory.Options options =newBitmapFactory.Options();
options.inJustDecodeBounds =true;
bitmap =BitmapFactory.decodeStream(stream,null, options);int imageHeight = options.outHeight;int imageWidth = options.outWidth;
options.inJustDecodeBounds =false;// recreate the stream// make some calculation to define inSampleSize
options.inSampleSize =?;Bitmap bitmap =BitmapFactory.decodeStream(stream,null, options);

你可以根據使用者手機螢幕的大小來計算圖片的尺寸,如下程式碼可以獲得手機裝置的尺寸。

DisplayMetrics metrics =newDisplayMetrics();((Activity) activity).getWindowManager().getDefaultDisplay().getMetrics(metrics);int screenWidth = metrics.widthPixels;int screenHeight =metrics.heightPixels;