1. 程式人生 > >Android:BitMap的效能優化

Android:BitMap的效能優化

最近維護一個專案,有一個功能是使用者可以從相機或是本地選擇頭像,經常會OOM,比較頭疼,於是查找了一些資料,自己總結一下對BitMap的優化:

1.BitMap及時回收

    Bitmap類的構造方法都是私有的,所以開發者不能直接new出一個Bitmap物件(called from JNI),只能通過BitmapFactory類的各種decode方法來例項化一個Bitmap。因為用到了JNI(Java Native Interface的縮寫,它提供了若干的API實現了Java和其他語言的通訊(主要是C&C++)),所以,載入 Bitmap到記憶體裡以後,是包含兩部分記憶體區域的,一部分是Java部分的,一部分是C部分的。這個Bitmap物件是由Java部分分配的,不用的時候系統就會自動回收了,但是那個對應的C可用的記憶體區域,虛擬機器是不能直接回收的,這個只能呼叫底層的功能釋放。所以BitMap提供了 recycle()方法來釋放C部分的記憶體。從Bitmap類的原始碼也可以看到,recycle()方法裡也的確是呼叫了JNI方法了的。

    所以,如果能夠獲得Bitmap物件的引用,就需要在不需要的時候(一般在Activity的onStop()或者onDestroy()中)呼叫Bitmap的recycle()方法來釋放Bitmap佔用的記憶體空間。(如果回收的時機不對,如在回收後又呼叫bitmap物件會報錯)。

// 先判斷是否已經回收 
if(bitmap != null && !bitmap.isRecycled()){   

        // 回收並且置為null 
        bitmap.recycle();   
        bitmap = null;   
}

2.快取

    有的時候App中可能大量相同的BitMap,如果每次都是重新建立一個BitMap,就會造成記憶體的浪費,這裡介紹兩個類。LruCache和DiskLruCache。
LruCache 為快取到記憶體中,這樣載入顯示比較快,例如ListView滑動不會有卡頓的情況,但是佔用記憶體,也可能被回收。
DiskLruCache 快取到磁碟,一般都是SDCard中,位置/sdcard/Android/data/<application package>/cache 

3.縮放和壓縮

    有的時候,我們用的圖片資源可能很大,但是,只是要顯示在頁面上一個很小的位置。我們就可以對其進行縮小。 BitmapFactory.Options 有一個屬性 inJustDecodeBounds,當設定為true後,在呼叫decode方法。不會把圖片讀到記憶體中,我們就可以獲得圖片的大小,然後很據顯示位置的大小設定其壓縮比inSampleSize(為1時不壓縮)。
        	// 設定了此屬性一定要記得將值設定為false
	        options.inJustDecodeBounds = true; 
	        Bitmap bitmap = null;
	        bitmap = BitmapFactory.decodeFile(url, options);
	        // 判斷200是否超過原始圖片高度
	        int be = (int) ((options.outHeight > options.outWidth ? options.outHeight / 150
	                : options.outWidth / 200));
	        // 如果超過,則不進行縮放
	        if (be <= 0) 
	            be = 1; 
	        options.inSampleSize = be;
	        options.inPreferredConfig = Bitmap.Config.ARGB_4444;
	        options.inPurgeable = true;
	        options.inInputShareable = true;
	        options.inJustDecodeBounds = false;// 再次使用時一定要設定成false,不然Bitmap為空
	        try {
	            bitmap = BitmapFactory.decodeFile(url, options);
	        } catch (OutOfMemoryError e) {
	            System.gc();
	            Log.e(TAG, "OutOfMemoryError");
	        }

然後是壓縮,compress(format, quality, stream),BitMap的compress方法的第二個引數,是壓縮比例,100表示不壓縮,越小壓縮越大。