http://stormzhang.github.io/android/2013/11/20/android-display-bitmaps-efficiently/ android
Android加載資源圖片時,很容易出現OOM的錯誤。
git
由於Android系統對內存有一個限制,若是超出該限制,就會出現OOM。爲了不這個問題,須要在加載資源時儘可能考慮如何節約內存,儘快釋放資源等等。github
Android系統版本對圖片加載,回收的影響:數組
1,在Android 2.3以及以後,採用的是併發回收機制,避免在回收內存時的卡頓現象。緩存
2,在Android 2.3.3(API Level 10)以及以前,Bitmap的backing pixel 數據存儲在native memory, 與Bitmap自己是分開的,Bitmap自己存儲在dalvik heap 中。致使其pixel數據不能判斷是否還須要使用,不能及時釋放,容易引發OOM錯誤。 從Android 3.0(API 11)開始,pixel數據與Bitmap一塊兒存儲在Dalvik heap中。併發
在加載圖片資源時,可採用如下一些方法來避免OOM的問題:spa
1,在Android 2.3.3以及以前,建議使用Bitmap.recycle()方法,及時釋放資源。code
2,在Android 3.0開始,可設置BitmapFactory.options.inBitmap值,(從緩存中獲取)達到重用Bitmap的目的。若是設置,則inPreferredConfig屬性值會被重用的Bitmap該屬性值覆蓋。orm
3,經過設置Options.inPreferredConfig值來下降內存消耗:圖片
默認爲ARGB_8888: 每一個像素4字節. 共32位。
Alpha_8: 只保存透明度,共8位,1字節。
ARGB_4444: 共16位,2字節。
RGB_565:共16位,2字節。
若是不須要透明度,可把默認值ARGB_8888改成RGB_565,節約一半內存。
4,經過設置Options.inSampleSize 對大圖片進行壓縮,可先設置Options.inJustDecodeBounds,獲取Bitmap的外圍數據,寬和高等。而後計算壓縮比例,進行壓縮。
5,設置Options.inPurgeable和inInputShareable:讓系統能及時回收內存。
inPurgeable:設置爲True,則使用BitmapFactory建立的Bitmap用於存儲Pixel的內存空間,在系統內存不足時能夠被回收,當應用須要再次訪問該Bitmap的Pixel時,系統會再次調用BitmapFactory 的decode方法從新生成Bitmap的Pixel數組。
設置爲False時,表示不能被回收。
inInputShareable:設置是否深拷貝,與inPurgeable結合使用,inPurgeable爲false時,該參數無心義。
True: share a reference to the input data(inputStream, array,etc) 。 False :a deep copy。
6,使用decodeStream代替其餘decodeResource,setImageResource,setImageBitmap等方法來加載圖片。
區別:
decodeStream直接讀取圖片字節碼,調用nativeDecodeAsset/nativeDecodeStream來完成decode。無需使用Java空間的一些額外處理過程,節省dalvik內存。可是因爲直接讀取字節碼,沒有處理過程,所以不會根據機器的各類分辨率來自動適應,須要在hdpi,mdpi和ldpi中分別配置相應的圖片資源,不然在不一樣分辨率機器上都是一樣的大小(像素點數量),顯示的實際大小不對。
decodeResource會在讀取完圖片數據後,根據機器的分辨率,進行圖片的適配處理,致使增大了不少dalvik內存消耗。
decodeStream調用過程:
decodeStream(InputStream,Rect,Options) -> nativeDecodeAsset/nativeDecodeStream
decodeResource調用過程:即finishDecode以後,調用額外的Java層的createBitmap方法,消耗更多dalvik內存。
decodeResource(Resource,resId,Options) -> decodeResourceStream (設置Options的inDensity和inTargetDensity參數) -> decodeStream() (在完成Decode後,進行finishDecode操做)
finishDecode() -> Bitmap.createScaleBitmap()(根據inDensity和inTargetDensity計算scale) -> Bitmap.createBitmap()
以上方法的組合使用,合理避免OOM錯誤。