第一種方法--及時回收bitmap內存:
一般而言,回收bitmap內存可以用到以下代碼
if(bitmap != null && !bitmap.isRecycled()){
bitmap.recycle();
bitmap = null;
}
System.gc();
bitmap.recycle()方法用於回收該bitmap所占用的內存,接着將bitmap置空,最后,別忘了用System.gc()調用一下系統的垃圾回收器。
在這里要聲明一下,bitmap可以有多個(以為着可以有多個if語句),但System.gc()最好只有一個(所以我將它寫在了if語句外),因為System.gc()
每次調用都要將整個內存掃描一遍,因而如果多次調用的話會影響程序運行的速度。為了程序的效率,我將它放在了所有回收語句之后,
這樣已經起到了它的效果,還節約的時間。
回收bitmap已經知道了,那么“及時”怎么理解呢?
根據我的實際經驗,bitmap發揮作用的地方要么在View里,要么在Activity里(當然肯定有其他區域,但是原理都是類似的),
回收bitmap的地方最好寫在這些區域剛剛不使用bitmap了的時刻。
比如說View如果使用了bitmap,就應該在這個View不再繪制了的時候回收,或者是在跳轉到的下一個區域的代碼中回收;
再比如說SurfaceView,就應該在onSurfaceDestroyed這個方法中回收;
同理,如果Activity使用了bitmap,就可以在onStop或者onDestroy方法中回收......
結合以上的共同點,“及時回收”的原理就是在使用了bitmap的區域結束時或結束后回收。
第二種方法--壓縮圖片:
這個方法當然很簡單了,就是使圖片體積大小變小,
可以有兩種方式:
一種是使圖片質量降低(分辨率不變),
另一種是使圖片分辨率降低(分辨率改變)。
總之,使圖片大小變小就行了。
實踐證明,使圖片質量降低(分辨率不變)可以大幅度地減小體積,而且質量的差異肉眼看上去並不明顯。
我剛開始使用的就是這兩種方法,原理很簡單,可是,我的BUG發生雖然沒那么頻繁了,但是它依然存在!!
后來經過幾天的努力與嘗試,結合我項目的一些具體情況,我終於解決了這個令人頭痛的BUG,但是事實卻有點出乎我的意料。
當我使用了上述兩種方法BUG依然還沒解決的時候,我開始懷疑,bitmap超過8M會報錯,可現在我把前前后后的bitmap都回收了,
不可能還有8M了,那為什么還會報錯呢?
終於我發現了這個原因:當內存中已經被一些bitmap使用過之后,無論被回收與否,它都會變得特別“敏感”,這個時候,
如果bitmap突然要占用大量的內存,即使和之前已經剩下的內存加起來不到8M,系統也會報錯,原因是它變“敏感”了!
我不知道這個用底層原理如何解釋比較好,但是我想“敏感”這個詞應該可以很形象地進行解釋。
於是,為了順應內存的“敏感性”,我將那個需要同時裝載多個大體積bitmap的地方進行了修改,用到了以下方法:
//壓縮,用於節省BITMAP內存空間--解決BUG的關鍵步驟
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 2; //這個的值壓縮的倍數(2的整數倍),數值越小,壓縮率越小,圖片越清晰
//返回原圖解碼之后的bitmap對象
bitmap = BitmapFactory.decodeResource(Context, ResourcesId, opts);
即先將圖片縮小一倍,再將這縮小了一倍的圖片作為bitmap存入內存,這樣一來,它占用的bitmap內存大大減小。
后來經測試,BUG果然解決了。圖片縮小一倍后,順應了內存的“敏感性”,也就不會再報錯了。
以上方法應該足以解決大多數bitmap內存溢出問題,但是具體情況還是要具體分析。