android常見異常(OOM異常)
阿新 • • 發佈:2019-01-09
首先,OOM就是記憶體溢位,即Out Of Memory。也就是說記憶體佔有量超過了VM所分配的最大。
怎麼解決OOM,通常OOM都發生在需要用到大量記憶體的情況下(建立或解析Bitmap,分配特大的陣列等),在這樣的一種情況下,就可能出現OOM,據我現在瞭解到,多數OOM都是因為Bitmap太大。所以,這裡我就專門針對如何解決Bitmap的OOM。其實最核發的就是隻載入可見範圍內的Bitmap,試想這樣一種情況,在GridView或ListView中,資料量有5000,每一屏只顯示20個元素,那麼不可見的,我們是不需要儲存Bitmap在內在中的。所以我們就是隻把那麼可見的Bitmap保留在記憶體中,那些不可見的,就釋放掉。當元素滑出來時,再去載入Bitmap。
這裡我有兩種方式,都可以避免OOM。
一,主動釋放Bitmap的記憶體
這種方式我簡單說一下,不太推薦,這也是我最開始使用的一種方法,但最後證明它不是最好的。(不推薦)
它的本質思路是:
1、只加載可見區域的Bitmap
2、滑動時不載入
3、停止滑動(Idle)後,開始重新載入可見區域的圖片
4、釋放滑出可見區域的Bitmap的內在。
它比較複雜:
1、我們需要監聽GridView/ListView的滑動事件,這個很簡單做到,AbsListView#setOnScrollListener(OnScrollListener l)
2、主動呼叫Bitmap#recycle()方法,它會導致一個問題,必須判斷這個Bitmap是否被一個View(ImageView等)所引用,如果被引用,我們不能簡單地呼叫recycle()方法,這樣會導致異常,說是View使用了一個已經被回收的Bitmap。
3,我們必須設計自己的執行緒來控制開始/暫停等,因為GridView/ListView的滑動狀態可能不斷地變化,也就是說滑動->停止->滑動,這種狀態可能不斷變化,這樣就會導致我們的執行緒中的run()方法裡面的邏輯比較複雜,一旦複雜,問題就可能就得更多。
基於以上幾點,這種方式不是最好的,所以不推薦。
二,設計Cache
這種方式,我覺得是比較好的一種,它首先利用了cache,我認為cache是一個很重要的東西,把Bitmap的記憶體單獨放在一個地方來管理,這個地方就是cache,它的容量是一定的,我們可能會不斷的向這個cache中新增元素,也可能不斷的移除元素。
為了更好的說明這種方式,先要介紹一下LruCache。
LruCache
1、這其實就是一個LinkedHashMap,任意時刻,當一個值被訪問時,它就會被移動到佇列的開始位置,所以這也是為什麼要用LinkedHashMap的原因,因為要頻繁的做移動操作,為了提高效能,所以要用LinkedHashMap。當cache滿了時,此時再向cache裡面新增一個值,那麼,在佇列最後的值就會從佇列裡面移除,這個值就有可能被GC回收掉。
2、如果我們想主動釋放記憶體,也是可以的,我們可以重寫entryRemoved(Boolean, K, V, V)方法。
3、這個類是執行緒安全的,在多執行緒下面使用這個類,沒不會存在問題。
- synchronized (cache) {
- if (cache.get(key) == null) {
- cache.put(key, value);
- }}
- AsyncTask例項必須在UI執行緒中建立
- execute(Params...)方法必須在UI執行緒中呼叫。
- 不用手動呼叫onPreExecute(), onPostExecute(), doInBackground(), onProgressUpdate()方法。
- 一個任務只能被執行一次。