Android:BitMap的效能優化
阿新 • • 發佈:2019-02-16
最近維護一個專案,有一個功能是使用者可以從相機或是本地選擇頭像,經常會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。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表示不壓縮,越小壓縮越大。