Canvas:尝试在 Android 2.3 上使用回收的位图 RuntimeException

Posted

技术标签:

【中文标题】Canvas:尝试在 Android 2.3 上使用回收的位图 RuntimeException【英文标题】:Canvas: trying to use a recycled bitmap RuntimeException on Android 2.3 【发布时间】:2013-06-25 11:13:48 【问题描述】:

我构建了一个自定义视图(类似于网格视图),它显示了许多许多图像,因此回收位图是此应用程序的必要条件。我正在使用 Lru 缓存(在下面实现)来处理位图回收。当我在 android 2.3 设备上测试这个(并快速滚动)时,我收到以下错误消息并且应用程序崩溃了。在弄清楚如何复制该错误后,我在 Android 4.0 上对其进行了测试,它运行良好。

06-27 10:57:48.420: E/AndroidRuntime(14255): FATAL EXCEPTION: main
06-27 10:57:48.420: E/AndroidRuntime(14255): java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@407fc6b8
06-27 10:57:48.420: E/AndroidRuntime(14255):    at android.graphics.Canvas.throwIfRecycled(Canvas.java:955)
06-27 10:57:48.420: E/AndroidRuntime(14255):    at android.graphics.Canvas.drawBitmap(Canvas.java:1044)
06-27 10:57:48.420: E/AndroidRuntime(14255):    at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:325)
06-27 10:57:48.420: E/AndroidRuntime(14255):    at android.widget.ImageView.onDraw(ImageView.java:872)
etc etc

我跟踪了这​​个错误,结果发现我在将位图设置为 ImageView 之前检查了位图是否被回收。但是,位图在该步骤和 draw() 步骤之间被回收,从而导致错误。

这是我的缓存:

 sLruCache = new LinkedHashMap(容量 / 2, 0.75f, true) 
      私有静态最终长序列版本UID = -7282875042976381535L;

      @覆盖
      protected boolean removeEldestEntry(LinkedHashMap.Entry eldest) 
        如果(大小()> mCapacity)
          返回真;
         别的
          返回假;
      

      公共位图删除(对象键)
        位图 bitmap = super.remove(key);
        如果(位图!= NULL_BITMAP)
          bitmap.recycle();
        
        返回位图;
      ;

      @覆盖
      公共无效清除()
        设置键 = new HashSet(keySet());
        对于(字符串键:键)
          位图映射 = get(key);
          如果(地图!= NULL_BITMAP)
            map.recycle();
          
        
        超级清除();
      
    ;

关于为什么这会在 Android 2.3 而不是 4.0 上失败的任何想法?

【问题讨论】:

bitmap.recycle() 您正在使用回收的位图。 只有当它被从缓存中删除时。我相信 bitmap.recycle() 应该在 remove 方法中使用。另外,为什么这会在 Android 4.0 上运行? developer.android.com/training/displaying-bitmaps/…。它将在 4.0 上运行,因为在 android 3.0 及更高版本中为位图分配内存的方式发生了变化 如果不在 remove 方法中,我应该什么时候回收它们?否则我会用完内存 当不再需要位图并且不能使用回收的位图时,您应该回收它。 【参考方案1】:

我也有同样的问题。

我不得不删除所有 Bitmap.recycle() 调用。有时会导致 OutOfMemoryException。

因此,我做了一个这样的 hack:

// when I need to remove bitmap from cache
if (Build.VERSION.SDK_INT < 9 || Build.VERSION.SDK_INT > 10) 
    bmp.recycle();
   

这不是一个好的解决方案,但它可能会有所帮助。

【讨论】:

以上是关于Canvas:尝试在 Android 2.3 上使用回收的位图 RuntimeException的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 上使图像透明?

RemoteServiceException 在 MIUI 11 上使我的应用程序崩溃

async Task.Run lambda 表达式在 Android 上使 Unity AR 应用程序崩溃,但在 iOS 上运行良好

如何在Web上使字体变薄

有没有办法创建从Android中的Canvas扩展的类?

在Android上将Canvas移植到OpenGL