文章目录

  • Glide使用背景
  • 使用方式一:into传入ImageView
    • 分析1:scaleType=fitXY是否会导致trying to use a recycled bitmap异常?
    • 分析2:into传入imageView是否会导致trying to use a recycled bitmap异常?
  • 使用方式二:into传入ViewTarget
    • 异常原因分析
    • 解决方案

Glide导致的RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap分析(基于Glide 4.9.0)

Glide使用背景

Glide在系统内存不足或者BitmapPool缓存池占满时,会回收内存缓存中的一部分Bitmap对象,并且调用bitmap.recycle()
bitmap.recycle()后,继续使用这个bitmap对象,会抛出异常
java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@9025008

  • Glide.with(mContext).load(imageUrl).apply(requestOptions).into(imageView);不会导致题中的问题。
  • Glide.with(mContext).load(imageUrl).apply(requestOptions).into(new ViewTarget);这种方式可能会导致抛出异常。

使用方式一:into传入ImageView

RequestOptions requestOptions = new RequestOptions().override(20, 60).placeholder(ContextCompat.getDrawable(mContext, R.color.background));
Glide.with(mContext).load(imageUrl).apply(requestOptions).into(imageView);

分析1:scaleType=fitXY是否会导致trying to use a recycled bitmap异常?

Glide在使用override(int width, int height)设置加载bitmap的大小时,会根据width和height中较小的值,和图片资源的width和height计算出缩放比例。举个例子:

  • 情形一:override(120, 40)

    当图片大小为 720 * 240,会根据height计算缩放比,即缩小6倍,那么加载到内存中bitmap宽高为 120 * 40

    当图片大小为 720 * 360,会根据height计算缩放比,即缩小9倍,那么加载到内存中bitmap宽高为 80 * 40

  • 情形二:override(20, 60)

    当图片大小为 720 * 240,会根据width计算缩放比,即缩小36倍,那么加载到内存中bitmap宽高为 20 * 6

    当图片大小为 720 * 360,会根据width计算缩放比,即缩小36倍,那么加载到内存中bitmap宽高为 20 * 10

通过上述分析,可以放心给ImageView设置scaleType=fitXY

分析2:into传入imageView是否会导致trying to use a recycled bitmap异常?

Glide在系统内存不足或者BitmapPool缓冲池占满时,会回收内存缓存中的一部分Bitmap对象,并且调用bitmap.recycle()
bitmap.recycle()后,继续使用这个bitmap对象,会抛出异常
java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@9025008

Glide使用into(imageView)的方式加载图片,不会抛出异常。into(imageView)中会调用到ImageViewTarget#onLoadCleared或者ImageViewTarget#onLoadStarted,这里面又调用了setResourceInternal(null)

public void onLoadStarted(@Nullable Drawable placeholder) {super.onLoadStarted(placeholder);setResourceInternal(null);setDrawable(placeholder);
}public void onLoadCleared(@Nullable Drawable placeholder) {super.onLoadCleared(placeholder);if (animatable != null) {animatable.stop();}setResourceInternal(null);setDrawable(placeholder);
}

setResourceInternal(null)最终会调用ImageView.setImageBitmap(null),然后再通过setDrawable(placeholder)设置默认占位图。因在into(imageView)中,最终调用到了ImageView.setImageBitmap(null),所以在异步加载图片之前把原先的bitmap对象清除了,所以UI重新绘制时不会用到已回收的recycled的bitmap对象。

调用栈debug截图如下:

使用方式二:into传入ViewTarget

RequestOptions requestOptions = new RequestOptions().override(mScreenWidth, mScreenWidth / 3).placeholder(ContextCompat.getDrawable(mContext, R.color.background));
Glide.with(mContext).load(imageUrl).apply(requestOptions).into(new ViewTarget<View, Drawable>(imageView) {@Overridepublic void onResourceReady(@NonNull Drawable drawable,Transition<? super Drawable> transition) {if (drawable instanceof BitmapDrawable) {Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();int height = bitmap.getHeight();int width = bitmap.getWidth();Log.d("width=" + width + ", height=" + height);}imageView.setBackground(drawable);}});

这种方式可能会导致抛出异常java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@9025008

异常原因分析

View有一个mBackground对象属性,是Drawable类型,这里的实际是BitmapDrawable,里面保存着Bitmap对象,mBackground中的Bitmap对象,同时也会被Glide缓存着,在Glide中随时可能会回收掉,并调用bitmap.recycle()

场景复现

把Glide的内存缓存设置的小一点。RecyclerView来回滑动会在Adapter中重新绑定数据,使用Glide重新加载图片,而Glide加载图片是异步的,子View在Glide回调onResourceReady回来之前就进行了绘制,子View调用draw(Canvas)方法中会调用drawBackgroud,此时使用的是原先的mBackground,但是此时mBackground中的bitmap可能已经被回收,即调用了bitmap.recycle(),所以就抛出异常了

解决方案

可以参考Glide的into(imageView)的处理方式,即在加载图片之前先调用该View的setBackground设置默认背景,imageView.setBackgroundResource(R.color.background)

// 加载之前先调用该View的setBackground设置默认背景
imageView.setBackgroundResource(R.color.background);
RequestOptions requestOptions = new RequestOptions().override(mScreenWidth, mScreenWidth / 3).placeholder(ContextCompat.getDrawable(mContext, R.color.background));
Glide.with(mContext).load(imageUrl).apply(requestOptions).into(new ViewTarget<View, Drawable>(imageView) {@Overridepublic void onResourceReady(@NonNull Drawable drawable,Transition<? super Drawable> transition) {if (drawable instanceof BitmapDrawable) {Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();int height = bitmap.getHeight();int width = bitmap.getWidth();Log.d("width=" + width + ", height=" + height);}imageView.setBackground(drawable);}});

异常调用栈如下:

06-25 17:29:04.890 17001 17001 E AndroidRuntime: FATAL EXCEPTION: main
06-25 17:29:04.890 17001 17001 E AndroidRuntime: Process: com.r.demo, PID: 17001
06-25 17:29:04.890 17001 17001 E AndroidRuntime: java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@9025008
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.graphics.BaseCanvas.throwIfCannotDraw(BaseCanvas.java:55)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.DisplayListCanvas.throwIfCannotDraw(DisplayListCanvas.java:226)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.RecordingCanvas.drawBitmap(RecordingCanvas.java:97)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:529)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.getDrawableRenderNode(View.java:19450)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.drawBackground(View.java:19386)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.draw(View.java:19183)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.updateDisplayListIfDirty(View.java:18142)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.draw(View.java:18920)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.updateDisplayListIfDirty(View.java:18133)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.draw(View.java:18920)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.support.v7.widget.RecyclerView.drawChild(RecyclerView.java:4820)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.draw(View.java:19195)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.support.v7.widget.RecyclerView.draw(RecyclerView.java:4219)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.updateDisplayListIfDirty(View.java:18142)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.draw(View.java:18920)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.draw(View.java:19195)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.updateDisplayListIfDirty(View.java:18142)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.draw(View.java:18920)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.updateDisplayListIfDirty(View.java:18133)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.draw(View.java:18920)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.updateDisplayListIfDirty(View.java:18133)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.draw(View.java:18920)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.updateDisplayListIfDirty(View.java:18133)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.draw(View.java:18920)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.draw(View.java:19195)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.updateDisplayListIfDirty(View.java:18142)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.draw(View.java:18920)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at com.r.demo.widget.swipebacklayout.SwipeBackLayout.drawChild(SwipeBackLayout.java:404)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.updateDisplayListIfDirty(View.java:18133)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.draw(View.java:18920)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.drawChild(ViewGroup.java:4236)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4022)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.View.updateDisplayListIfDirty(View.java:18133)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:669)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:675)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:783)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewRootImpl.draw(ViewRootImpl.java:3013)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2827)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2380)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1413)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6781)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.Choreographer.doCallbacks(Choreographer.java:723)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.Choreographer.doFrame(Choreographer.java:658)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.os.Handler.handleCallback(Handler.java:790)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.os.Handler.dispatchMessage(Handler.java:99)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.os.Looper.loop(Looper.java:164)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at android.app.ActivityThread.main(ActivityThread.java:6523)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at java.lang.reflect.Method.invoke(Native Method)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
06-25 17:29:04.890 17001 17001 E AndroidRuntime:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:819)

Glide导致的RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap相关推荐

  1. 【Bitmap】Canvas: trying to use a recycled bitmap android.graphics.Bitmap问题

    Canvas: trying to use a recycled bitmap android.graphics.Bitmap问题 我这用到bitmap中间变量了,还用到 Bitmap bitmap ...

  2. Android java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@

    一.Bitmap经常会遇到的问题.  二.使用注意事项 mImageVew = (ImageView) findViewById(R.id.imageView); Bitmap bitmap = Bi ...

  3. java.lang.RuntimeException:Canvas: trying to use a recycled bitmap

    android官方: 只有当您确定位图已不再使用时才应该使用 recycle().如果您调用 recycle() 并在稍后尝试绘制位图,则会收到错误:"Canvas: trying to u ...

  4. java.lang.RuntimeException: Canvas: trying to draw too large(203212800bytes) bitmap.

    java.lang.RuntimeException: Canvas: trying to draw too large(203212800bytes) bitmap. 异常原因分析:Canvas绘制 ...

  5. canvas.drawBitmap()画出来的bitmap和原bitmap大小不同,有一部分缺失了

    造成这个问题的原因就在于安卓系统会根据bitmap的density和当前运行设备的density进行比较,不同会进行缩放. 项目里的图片叫 ic_launcher.png,大小是72*72,只有一张, ...

  6. Android使用Bitmap、Canvas制作图片

    转载请注明来源:http://blog.csdn.net/kjunchen/article/details/51794037 Android使用Bitmap.Canvas制作图片 先看下效果图: 在开 ...

  7. 慎用Glide preload

    Glide preload 机制 一般情况下,当我们想提前预加载一张图片到内存的时候,经常会使用Glide 来预加载,如: Glide.with(context).load(url).diskCach ...

  8. Android规范发展

    一.Android 编码规范 1.java 代码中不出现中文.最多凝视中能够出现中文 2.局部变量命名.静态成员变量命名 仅仅能包括字母,单词首字母出第一个外,都为大写,其它字母都为小写 3.常量命名 ...

  9. android 开发规范1

    Android开发规范 一.Android编码规范 1.java代码中不出现中文,最多注释中可以出现中文 2.局部变量命名.静态成员变量命名 只能包含字母,单词首字母出第一个外,都为大写,其他字母都为 ...

  10. Android客户端内置内存工具进行崩溃定位的实践经验

    前言 本宝宝苦啊,辛辛苦苦上线一个版本,上线之后,看到崩溃日志,感觉整个人都不好了. 别人家的崩溃日志是这样子的: 1 Fatal Exception: java.lang.NullPointerEx ...

最新文章

  1. socket编程和并发服务器
  2. 我人生的第一个博客,真正的博客。
  3. Ubuntu系统安装(win7双系统)
  4. IOS时间与日期处理
  5. XManager 远程连接Netbackup图形用户界面
  6. hackintosh黑苹果_为什么您的下一个Mac应该是Hackintosh?
  7. 如何让html引用公共的头部和尾部(多个html文件公用一个header.html和footer.html)
  8. 基于matlab边缘提取的几种方法的比较
  9. java优化 pdf_Java性能优化权威指南 PDF扫描[132MB]
  10. 《炬丰科技-半导体工艺》 光学镜片和玻璃部件的超声波清洗
  11. UE4联网机制和多人游戏总结 (第一部分)
  12. android 电视 刷机,康佳电视通用刷机救砖教程分享
  13. 多款iPhone遭遇中国禁售令!福建法院判决高通胜诉苹果
  14. excel vba 去重
  15. 《MySQL是怎么样运行的》读书笔记一 数据页+索引
  16. Kodu程序的菜单---Kodu少儿编程第七天
  17. 数学建模用python分析gdp_数学建模·中国GDP趋势分析与预测
  18. 博览——万维网的发明者—蒂姆•伯纳斯-李 (一)
  19. 图形相关知识(显示)
  20. Facebook再现丑闻,约100位应用程序开发人员偷看用户数据

热门文章

  1. Python 基础 1加到100 求和
  2. 揭秘网上到处晒淘宝客月收入过万的真相
  3. 抖音用什么编程语言_抖音app软件开发流程是什么,主要运用的开发工具以及语言是什么?...
  4. c语言定义数组中字母怎么输入,c语言数组怎么输入?
  5. Road_slam论文阅读及理解
  6. 管理理论模型:PEST、5W2H、时间管理、生命周期、逻辑树、金字塔、SMART原则
  7. Excel自动插入jpg图片或png图片 VBA 工具 模块
  8. 学习-Java输入输出之字符缓冲IO流之往文件中插入分隔符
  9. 解除开启全局 UWP应用网络隔离限制
  10. 使用Excel在图片上添加正方形网格线