Bitmap回收—Canvas: trying to use a recycled bitmap android.graphics

Penny-聽海發表於2018-03-20

bitmap 回收時


/**
 * onDestroy方法
 * */

@Override
protected void onDestroy() {
super.onDestroy();
BitmapToBase.recycleBitmap(bitmap);
}




/**
 * 回收bitmap
* */




public static void recycleBitmap(Bitmap bitmap){
if(bitmap!=null){
if(!bitmap.isRecycled()){ 
bitmap.recycle();  

}
}




偶爾報錯 錯誤如下


java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@f08cd43
at android.graphics.Canvas.throwIfCannotDraw(Canvas.java:1270)
at android.graphics.Canvas.drawBitmap(Canvas.java:1404)
at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:544)
at android.widget.ImageView.onDraw(ImageView.java:1244)
at android.view.View.draw(View.java:16669)
at android.view.View.updateDisplayListIfDirty(View.java:15622)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.draw(View.java:16681)
at android.view.View.updateDisplayListIfDirty(View.java:15622)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.draw(View.java:16681)
at android.view.View.updateDisplayListIfDirty(View.java:15622)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.draw(View.java:16681)
at android.view.View.updateDisplayListIfDirty(View.java:15622)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.draw(View.java:16681)
at android.view.View.updateDisplayListIfDirty(View.java:15622)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.widget.ListView.drawChild(ListView.java:3609)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.widget.AbsListView.dispatchDraw(AbsListView.java:2800)
at android.widget.ListView.dispatchDraw(ListView.java:3604)
at android.view.View.draw(View.java:16681)
at android.widget.AbsListView.draw(AbsListView.java:4749)
at android.view.View.updateDisplayListIfDirty(View.java:15622)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.draw(View.java:16681)
at android.view.View.updateDisplayListIfDirty(View.java:15622)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.updateDisplayListIfDirty(View.java:15614)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.draw(View.java:16681)
at android.widget.ScrollView.draw(ScrollView.java:1900)
at android.view.View.updateDisplayListIfDirty(View.java:15622)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.draw(View.java:16681)
at android.view.View.updateDisplayListIfDirty(View.java:15622)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.updateDisplayListIfDirty(View.java:15614)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.updateDisplayListIfDirty(View.java:15614)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at com.android.internal.policy.PhoneWindow$DecorView.dispatchDraw(PhoneWindow.java:2794)
at android.view.View.updateDisplayListIfDirty(View.java:15614)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.updateDisplayListIfDirty(View.java:15614)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.updateDisplayListIfDirty(View.java:15614)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.updateDisplayListIfDirty(View.java:15614)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.updateDisplayListIfDirty(View.java:15614)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at android.view.View.updateDisplayListIfDirty(View.java:15614)
at android.view.View.draw(View.java:16423)
at android.view.ViewGroup.drawChild(ViewGroup.java:3735)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3525)
at com.android.internal.policy.PhoneWindow$DecorView.dispatchDraw(PhoneWindow.java:2794)
at android.view.View.draw(View.java:16681)
at com.android.internal.policy.PhoneWindow$DecorView.draw(PhoneWindow.java:2780)
at android.view.View.updateDisplayListIfDirty(View.java:15622)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:286)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:292)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:327)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:3088)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2892)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2504)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1335)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6869)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:894)
at android.view.Choreographer.doCallbacks(Choreographer.java:696)
at android.view.Choreographer.doFrame(Choreographer.java:631)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:880)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5917)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:749)






用處


imageview.setDrawingCacheEnabled(true);
bitmap=Bitmap.createBitmap(imageview.getDrawingCache());
imageview.setDrawingCacheEnabled(false);


即 在imagview 上顯示圖片 點選按鈕 儲存imageview上的圖片 




解決方法


自定義Imageview 重寫ondraw方法 再次捕獲異常


/**
* onDraw 方法 捕獲異常(圖片回收時)
 * */



@Override
protected void onDraw(Canvas canvas) {
try{
super.onDraw(canvas);
}catch (Exception e){
System.out.println("ImageView->onDraw() Canvas: trying to use a recycled bitmap");
}
}








還看到其他用法的解決方法


Bitmap bitmap = Bitmap.createBitmap(temp, 0, 0, width, height, matrix,true);方法了。
把temp.recycle();後就報了那個錯誤。
 
原因是傳入的temp圖片和新的bitmap圖片解析度一樣。createBitmap的原始碼就會直接返回temp物件,而不是新建一個bitmap物件,這樣temp.recycle()被回收後,bitmap自然也被回收了。
解決方法把傳入圖片換個解析度。
或者使 width, height, 和生成matrix的width, height不一樣,就行了
 
if(newHeight==height&&newWidth==width){
//強制使新舊圖片解析度不一樣,防止temp和bitmap是同一物件
height=height-1;
}