最近压力测试的时候遇到上面的这个问题,具体错误又不报哪一行错误;
错误日志如下:
Short Msg: java.lang.RuntimeException
Long Msg: java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@4630f45
Build Label: google/sdk_gphone_x86/generic_x86:8.1.0/OSM2.171116.002/4458339:user/release-keys
Build Changelist: 4458339
Build Time: 1510952710000
java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@4630f45
at android.graphics.BaseCanvas.throwIfCannotDraw(BaseCanvas.java:55)
at android.view.DisplayListCanvas.throwIfCannotDraw(DisplayListCanvas.java:226)
at android.view.RecordingCanvas.drawBitmap(RecordingCanvas.java:97)
at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:529)
at android.widget.ImageView.onDraw(ImageView.java:1349)
at android.view.View.draw(View.java:19192)
at android.view.View.updateDisplayListIfDirty(View.java:18142)
at android.view.View.draw(View.java:18920)
at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
at android.view.View.draw(View.java:19195)
at android.support.v4.view.ViewPager.draw(ViewPager.java:2443)
at android.view.View.updateDisplayListIfDirty(View.java:18142)
at android.view.View.draw(View.java:18920)
at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
at android.view.View.draw(View.java:19195)
at android.view.View.updateDisplayListIfDirty(View.java:18142)
at android.view.View.draw(View.java:18920)
at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
at android.view.View.updateDisplayListIfDirty(View.java:18133)
at android.view.View.draw(View.java:18920)
at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
at android.view.View.updateDisplayListIfDirty(View.java:18133)
at android.view.View.draw(View.java:18920)
at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
at android.view.View.draw(View.java:19195)
at com.android.internal.policy.DecorView.draw(DecorView.java:788)
at android.view.View.updateDisplayListIfDirty(View.java:18142)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:669)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:675)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:783)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2992)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2806)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2359)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1392)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6752)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
at android.view.Choreographer.doCallbacks(Choreographer.java:723)
at android.view.Choreographer.doFrame(Choreographer.java:658)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
发了很多群,一直找不到什么原因造成的,检查代码也没看出毛病.后来看了这篇文章:
转载自:https://blog.youkuaiyun.com/vipqiangqiang/article/details/60583289
在最近一个项目中,因为要使用AnimationDrawable进行动画播放,图片质量都比较大,而且播放的频率会很多,开发的行车记录仪的内存又有限,刚开始并没有将Bitmap recycle掉,所以出现了OOM的异常。为了解决内存溢出问题,在退出当前页面的时候,将Bitmap recycle掉。但是在此又遇到了另外一个问题,退出当前界面再进入这个页面的时候会报出 trying to use a recycled bitmap android.graphics.Bitmap@41d的异常。
此后看了很多文章,但是都并不能真正的解决这个问题,只能从源码查起了。
分析问题出现原因是在我们加载drawable的时候可能bitmap recycle后,被再次使用,所以导致此问题的出现。跟踪一下源代码 getResource(context).getDrawable(id)==继续进入代码==>loadDrawable(value, id);在这个里面我们可以看到关键代码
- Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key);
- if (dr != null) {
- return dr;
- }
在此可以看出,如果缓存Drawable不为空,那么就返回原先使用的Drawable,在我们这里,这个Drawable引用的Bitmap已经被recycle了,但是Drawable这个缓存对象是一直并引用那个失效的Bitmap。其实系统这样设计我们可以理解,为了不用再次加载这个Bitmap为了节省系统资源,但在我们此处因为要使用到大量图片来播放动画(也有别的需求只是加载大图片,防止内存溢出,所以退出页面时recycle这个图片),所以系统的这种方法对我们来说是会适得其反的。
找到问题的要点,那么我们着手开始解决这个问题
1、在退出页面执行onDestory()回调的时候,回收图片资源以及把AnimationDrawable的对象置空,并调用GC让系统尽快回收
- @Override
- protected void onDestroy() {
- super.onDestroy();
- //资源回收否则会造成内存溢出
- tryRecycleAnimationDrawable(animation);
- AnimationDrawble置空
- animation = null;
- 把针对AnimationDrawble的引用置空
- tv.setBackground(null);
- 系统垃圾回收
- System.gc();
- }
- //把AnimationDrawable中的图片资源逐个回收
- private void tryRecycleAnimationDrawable(
- AnimationDrawable animationDrawables) {
- if (animationDrawables != null) {
- animationDrawables.stop();
- for (int i = 0; i < animationDrawables.getNumberOfFrames(); i++) {
- Drawable frame = animationDrawables.getFrame(i);
- if (frame instanceof BitmapDrawable) {
- Bitmap bitmap = ((BitmapDrawable) frame).getBitmap();
- bitmap.recycle();
- bitmap = null;
- }
- frame.setCallback(null);
- }
- animationDrawables.setCallback(null);
- }
- }
2、重点在再次进入程序后如果不再调用cacheDrawable很遗憾的是我们默认的加载系统资源的方法getResource(context).getDrawable(id)默认会调用该方法来加载资源,我们只能另辟捷径了。使用系统最原始方法加载图片资源 BitmapFactory.decodeResource(Resources, resId);
不过此方法如果图片资源大会很容易在这里造成OOM,对这块儿的处理暂时省略,相信读到这篇文章的童鞋自会知道怎么处理。在这里得到最新的Bitmap后,new AnimationDrawable并把bitmap加载进去就OK
由于每个人使用场景不同,业务也不一样,如果上面仍然不能解决你们的问题,所以有几个博客做为参考:
http://blog.youkuaiyun.com/u010829905/article/details/50233207 Android bitmap.recycle()导致trying to use a recycled bitmap报错分析
http://blog.youkuaiyun.com/yaya_soft/article/details/44064249 Android手动回收bitmap,引发Canvas: trying to use a recycled bitmap处理
http://blog.youkuaiyun.com/sex_34/article/details/47725707 Canvas: trying to use a recycled bitmap android.graphics.Bitmap@XXX
最后结尾:
我说说看了这篇的感受,如果是质量很大的图片,不如引导页加载,这篇解决不了我的问题,只能告诉我问题出在哪里,目前我也没有找到合适的解决办法,大量压力测试下,几万次点击,就会出现一次这个问题!一直没有得到妥善解决,问题先放在这,如果有大神看到这篇文章,并且能够有好的解决办法,请告知我,必有重谢!
在Android开发中,遇到尝试使用已回收的Bitmap异常。通过分析,发现是Bitmap回收后,缓存的Drawable仍引用它。解决方案包括在onDestroy()时回收资源,以及使用BitmapFactory.decodeResource()避免缓存。文章提供了多个参考链接以帮助开发者解决问题。
4650

被折叠的 条评论
为什么被折叠?



