1. 程式人生 > >Android 載入打圖片出現OOM異常的處理方式

Android 載入打圖片出現OOM異常的處理方式

在很多的Android專案中都會出現載入網路圖片或是載入本地SD卡中的圖片導致應用出現OOM異常,應用掛死的現象。查了很多資料,終於對應用的OOM做出了一定程度的優化。故寫出來大家都分享一下。

OOM(Out Of Memory )異常 ,顧名思義這個異常是說你的記憶體不夠用或者耗盡了,在Android中,一個Process 只能使用16M記憶體,如果超過了這個限制就會跳出這個異常。這樣就要求我們要時刻想著釋放資源System.gc();值得注意的是Bitmap在不用時,一定要recycle,不然OOM是非常容易出現的。

查了很多資料,有說是強制增大應用的記憶體空間,有說是使用軟引用及弱引用試得虛擬機器更好更快的實現記憶體回收機制,全都用了,可OOM異常依然存在。這是為什麼呢?

最後檢視API原始碼才發現:

當使用 imageView.setBackgroundResource,imageView.setImageResource, 或者BitmapFactory.decodeResource 、BitmapFactory.decodeFile 這樣的方法來設定一張大圖片的時候,這些函式在完成decode後,最終都是通過java層的createBitmap來完成的,需要消耗更多記憶體。
因此,改用先通過BitmapFactory.decodeStream方法解流的方式,創建出一個bitmap,再將其設為ImageView的 source,decodeStream最大的祕密在於其直接呼叫JNI>>nativeDecodeAsset()來完成decode,無需再使用java層的createBitmap,從而節省了java層的空間。如果在讀取時加上圖片的Config引數,可以跟有效減少載入的記憶體,從而跟有效阻止拋out of Memory異常。
另外,需要特別注意: decodeStream是直接讀取圖片資料的位元組碼了, 不會根據機器的各種解析度來自動適應,使用了decodeStream之後,需要在hdpi和mdpi,ldpi中配置相應的圖片資源,否則在不同解析度機器上都是同樣大小(畫素點數量),顯示出來的大小就不對了。



此處提供幾種圖片設定的方式:

1.得到資原始檔中的圖片bitmap

  /**
   * 得到資原始檔中的圖片bitmap
   * @param context
   * @param resId
   * @return Bitmap
   */
  public static Bitmap readBitMap(Context context, int resId){  
	BitmapFactory.Options opt = new BitmapFactory.Options();  
	opt.inPreferredConfig = Bitmap.Config.RGB_565;   
	opt.inPurgeable = true;  
	opt.inInputShareable = true;  
	InputStream is = context.getResources().openRawResource(resId);
	Bitmap bm = BitmapFactory.decodeStream(is,null,opt);
	return bm;  
  }

2.   通過DecodeFile解析SD卡中的圖片 

  	/**
	 * 通過DecodeFile解析SD卡中的圖片 
	 * @param file
	 * @return Bitmap
	 */
	public static Bitmap getBitmapByDecodeFile(File file){
		Bitmap newBit = null;
		 try {
            FileInputStream fis = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(fis);
            Bitmap bitmap= BitmapFactory.decodeStream(bis);
            newBit  = Bitmap.createScaledBitmap(bitmap, 180, 180, false);
            bis.close();
            fis.close();
         }  catch (Exception e) {
        	   e.printStackTrace();
         }
		 return newBit;
	}
3.在設定imageView的background的時候沒有setImageBitmap(bitmap)方法,但是有img.setBackgroundDrawable(bitmapDrawale)方法

故我們還需要通過得到的bitmap在去獲取他的bitmapDrawable

BitmapDrawable bmdrawable = new BitmapDrawable(context.getResources(), bitmap);

最後得到了bitmap後就可以通過img.setImageBitmap(bitmap)或者是img.setBackgroundDrawable(bitmapDrawale)將圖片設定到imageView中去。

至此,應用中出現的OOM異常就基本解決。