如何解决“canvas:试图使用回收的位图错误”?

我正在创build一个RecyclerView来显示图片的网格。 当select其中一个时,它应该打开一个转换的新活动。

我正在使用Glide库来加载图片,转换看起来很糟糕,因为它在新的活动中重新加载图片。 所以我不得不把它保存在caching中,然后用它来转换。

我有代码,但有时如果图片不加载,它会抛出一个Canvas的RuntimeException。

这是日志:

 07-03 15:19:58.633 28461-28461/jahirfiquitiva.project E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: jahirfiquitiva.project, PID: 28461 java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@29f09d20 at android.graphics.Canvas.throwIfCannotDraw(Canvas.java:1282) at android.view.GLES20Canvas.drawBitmap(GLES20Canvas.java:599) at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:538) at android.widget.ImageView.onDraw(ImageView.java:1176) at android.view.View.draw(View.java:15239) at android.view.View.updateDisplayListIfDirty(View.java:14175) at android.view.View.getDisplayList(View.java:14197) at android.view.GhostView.onDraw(GhostView.java:52) at android.view.View.draw(View.java:15239) at android.view.View.updateDisplayListIfDirty(View.java:14175) at android.view.View.getDisplayList(View.java:14197) at android.view.View.draw(View.java:14967) at android.view.ViewGroup.drawChild(ViewGroup.java:3406) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3199) at android.view.View.updateDisplayListIfDirty(View.java:14170) at android.view.View.getDisplayList(View.java:14197) at android.view.View.draw(View.java:14967) at android.view.ViewGroup.drawChild(ViewGroup.java:3406) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3199) at android.view.ViewOverlay$OverlayViewGroup.dispatchDraw(ViewOverlay.java:219) at android.view.View.draw(View.java:15248) at android.widget.FrameLayout.draw(FrameLayout.java:598) at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2906) at android.view.View.updateDisplayListIfDirty(View.java:14175) at android.view.View.getDisplayList(View.java:14197) at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:273) at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:279) at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:318) at android.view.ViewRootImpl.draw(ViewRootImpl.java:2536) at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2352) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1982) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5891) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767) at android.view.Choreographer.doCallbacks(Choreographer.java:580) at android.view.Choreographer.doFrame(Choreographer.java:550) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5289) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699) 

这是打开其他活动并将图片保存为caching的代码:

 private void openViewer(WallpapersAdapter.WallsHolder wallsHolder, int index, final HashMap<String, String> data) { final Intent intent = new Intent(wallsActivity, ViewerActivity.class); intent.putExtra("wallUrl", data.get(WallpapersActivity.WALL)); intent.putExtra("wallName", data.get(WallpapersActivity.NAME)); intent.putExtra("transitionName", ViewCompat.getTransitionName(wallsHolder.wall)); //save image from drawable //get its path and send it to activity Bitmap bitmap = drawableToBitmap(wallsHolder.wall.getDrawable()); //Convert to byte array and send to the other activity Log.e("Resolution", bitmap.getWidth() + "x" + bitmap.getHeight()); try { //Write file String filename = "bitmap.png"; FileOutputStream stream = this.openFileOutput(filename, Context.MODE_PRIVATE); bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); //Cleanup stream.close(); bitmap.recycle(); //Pop intent intent.putExtra("image", filename); } catch (Exception e) { e.printStackTrace(); } ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation( this, wallsHolder.wall, ViewCompat.getTransitionName(wallsHolder.wall)); startActivity(intent, options.toBundle()); } public static Bitmap drawableToBitmap (Drawable drawable) { Bitmap bitmap = null; if (drawable instanceof BitmapDrawable) { BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; if(bitmapDrawable.getBitmap() != null) { return bitmapDrawable.getBitmap(); } } if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) { bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel } else { bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); } Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); drawable.draw(canvas); return bitmap; } 

我能做些什么来解决这个问题? 提前致谢。

Solutions Collecting From Web of "如何解决“canvas:试图使用回收的位图错误”?"

我怀疑有一段时间你的位图进入可回收状态就在Canvas有机会在这里drawable.draw(canvas);

一个快速的解决scheme应该不要调用bitmap.recycle(); ,这对于android> 2.3.3不是严格要求的。 如果你仍然想强制回收这个内存,你必须find一种方法来检查位图是否真的不再需要(即Canvas有机会完成绘图操作)。

移动bitmap.recycle(); 到代码中的另一个地方,这个位图实际上不再需要了。

我不太了解canvas(我不经常使用animation),但是如果你没有find解决这个问题的方法,你可以尝试使用这个库: https : //github.com/codepath/android_guides /维基/共享元素活性化转变