Canvas:尝试在Android 2.3上使用循环位图RuntimeException

时间:2013-06-27 19:41:18

标签: android bitmap lru

我构建了一个自定义视图(类似于网格视图),可以显示许多图像,因此回收Bitmaps是此应用程序的必需品。我正在使用Lru缓存(在下面实现)来处理Bitmap回收。当我在Android 2.3设备上测试它(并快速滚动)时,我收到以下错误消息,应用程序崩溃了。在弄清楚如何复制bug之后,我在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之前,我检查了Bitmap是否被回收。但是,Bitmap在该步骤和draw()步骤之间被回收,从而导致错误。

这是我的缓存:

 sLruCache =    new LinkedHashMap(capacity / 2, 0.75f, true) {
      private static final long serialVersionUID = -7282875042976381535L;

      @Override
      protected boolean removeEldestEntry(LinkedHashMap.Entry eldest) {
        if (size() > mCapacity) {
          return true;
        } else
          return false;
      }

      public Bitmap remove(Object key) {
        Bitmap bitmap = super.remove(key);
        if (bitmap != NULL_BITMAP) {
          bitmap.recycle();
        }
        return bitmap;
      };

      @Override
      public void clear() { 
        Set keys = new HashSet(keySet());
        for (String key : keys) {
          Bitmap map = get(key);
          if (map != NULL_BITMAP) {
            map.recycle();
          }
        }
        super.clear();
      }
    };

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

1 个答案:

答案 0 :(得分:0)

我有同样的问题。

我必须删除所有Bitmap.recycle()调用。它有时会导致OutOfMemoryException。

因此,我这样做了一个黑客:

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

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