天天看點

解決Bitmap recycle異常:Canvas: trying to use a recycled bitmap android.graphics.Bitmap Bitmap回收異常:Canvas: trying to use a recycled bitmap android.graphics.Bitmap解決

Bitmap回收異常:Canvas: trying to use a recycled bitmap android.graphics.Bitmap解決

今天測試程式發現程式偶爾會異常崩潰,後來發現可能是有3個Bitmap對象沒有回收,占了一部分記憶體,在手機記憶體不多的時候程式就崩掉了,

後來對Bitmap對象統一進行了isRecycled,這樣能加速系統對無用資源的回收,但發現還是有問題:Canvas: trying to use a recycled bitmap android.graphics.Bitmap,

最後的解決辦法是在isRecycled前對Bitmap進行一個非空和是否isRecycled的判斷,問題搞定。

注:網友說可以不必回收gc會自動回收,看了一些資料後總結recycle是native方法,不是java代碼産生的,回收還是有必要的。

在做Android的開發的時候,在ListView 或是 GridView中需要加載大量的圖檔,為了避免加載過多的圖檔引起OutOfMemory錯誤,設定了一個圖檔緩存清單 Map<String, SoftReference<Bitmap>> imageCache , 并對其進行維護,在圖檔加載到一定數量的時候,就手動回收掉之前加載圖檔的bitmap,此時就引起了如下錯誤:

檢視文本 列印 ?

  1. java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@41de4380  
  2.     at android.graphics.Canvas.throwIfRecycled(Canvas.java:1026)  
  3.     at android.graphics.Canvas.drawBitmap(Canvas.java:1127)  
  4.     at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:393)  
  5.     at android.widget.ImageView.onDraw(ImageView.java:961)  
  6.     at android.view.View.draw(View.java:13458)  
  7.     at android.view.View.draw(View.java:13342)  
  8.     at android.view.ViewGroup.drawChild(ViewGroup.java:2929)  
  9.     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799)  
  10.     at android.view.View.draw(View.java:13461)  
  11.     at android.view.View.draw(View.java:13342)  

圖檔手動回收部分代碼:

檢視文本 列印 ?

  1. Bitmap removeBitmap = softReference.get();  
  2. if(removeBitmap != null && !removeBitmap.isRecycled()){  
  3.     removeBitmap.recycle(); //此句造成的以上異常  
  4.     removeBitmap = null;  
  5. }  

網上有好多人說應該把recycle()去掉,個人認為去掉後會引起記憶體持續增長,雖然将bitmap設定為了null,但是系統并沒有對其進行真正的回收,仍然占有記憶體,即是調用了System.gc() 強制回後以後,記憶體仍然沒有下去,如果依靠記憶體達到上限時系統自己回收的話,個人覺得太晚了,已經對應用造成了影響,應用應該是比較卡了,是以還是贊同加上bitmap.recycle() ,但是又會引起  Canvas: trying to use a recycled bitmap 異常,困擾了很久,開始嘗試從其它方面着手來解決這個問題,即然是異常就應該能夠捕獲到,但是在Adapter裡的getView()方法裡進行捕獲的時候,時機晚了,沒有捕獲到。現在換到在ImageView的onDraw()裡進行捕獲,上面的異常能夠捕獲。

解決方法(繼承ImageView 重寫onDraw()方法,捕獲異常):

在重寫onDraw()方法中,其實什麼都沒有做,隻是添加了一個異常捕獲,即可捕捉到上面的錯誤

檢視文本 列印 ?

  1. import android.content.Context;  
  2. import android.graphics.Canvas;  
  3. import android.util.AttributeSet;  
  4. import android.widget.ImageView;  
  5. public class MyImageView extends ImageView {  
  6.     public MyImageView (Context context, AttributeSet attrs) {  
  7.         super(context, attrs);  
  8.     }  
  9.     @Override  
  10.     protected void onDraw(Canvas canvas) {  
  11.         try {  
  12.             super.onDraw(canvas);  
  13.         } catch (Exception e) {  
  14.             System.out  
  15.                     .println("MyImageView  -> onDraw() Canvas: trying to use a recycled bitmap");  
  16.         }  
  17.     }  
  18. }  

在開發項目的時候 出現了Canvas: trying to use a recycled bitmap android.graphics.Bitmap一個異常。在網上看了很多資料。有的說傳入圖檔和新的bitmap圖檔分辨率一樣,強行改變圖檔的分辨率就不會出現異常了。可是問題還是解決不了。後來看bitmap.recycle()的官方介紹:

Free the native object associated with this bitmap, and clear the reference to the pixel data. This will not free the pixel data synchronously; it simply allows it to be garbage collected if there are no other references. The bitmap is marked as "dead", meaning it will throw an exception if getPixels() or setPixels() is called, and will draw nothing. This operation cannot be reversed, so it should only be called if you are sure there are no further uses for the bitmap. This is an advanced call, and normally need not be called, since the normal GC process will free up this memory when there are no more references to this bitmap. 

大體意思是這個函數不是必須要調用的。

後來我直接把代碼改成了

if (bitmap != null && !bitmap.isRecycled()) 

     bitmap=null;

}     

直接給他賦空了。最後就解決了。出現了這個問題的朋友可以試試這種方法。或許能夠幫到你們。。。