缓存位图 - 检查当前VM预算

时间:2012-03-08 12:11:28

标签: android caching architecture bitmap out-of-memory

我想知道是否有人在架构中有任何经验,这些架构旨在动态发现尽可能多的图像。

在我的情况下,我为从ListView点击的每个项目请求一个Bitmap。这些位图是通过网络接收的(在处理或网络I / O方面不是便宜的操作)。用户可能会从列表中加载一些项目,在它们之间切换。我缓存这些图像,以便后续的项目请求将导致立即加载位图:

private Bitmap bitmap = null;
public Bitmap getBitmap(int id) {
    if(bitmap == null) bitmap = expensiveNetworkOperationToGetBitmap(id);
    return bitmap;
}

(请忽略线程阻止问题)

但是,用户完全可以浏览很多项目。每个人慢慢占用一块内存,最终超出预算并崩溃应用程序。

这让我提出了一个问题:是否可以动态检测缓存何时达到限制?如果是这样,应该可以在添加新图像时开始销毁旧图像。请参阅下面的示例代码:

private HashMap<Integer, Bitmap> bitmaps = new HashMap<Integer, Bitmap>();
public Bitmap getBitmap(int id) {
    Bitmap bitmap;
    if(!bitmaps.contains(id)) {
        if(// Bitmap budget close to being exeeded?) {
            bitmaps.keyValues().get(0).recycle();
            bitmaps.remove(bitmaps.keyValues().get(0));
        }
        bitmap = expensiveNetworkOperationToGetBitmap(id);
        bitmaps.put(id, bitmap);
    else {
        bitmap = bitmaps.get(id);
    }
    return bitmap;
}

再次请忽略对从HashMap弹出第一个Bitmap的无效性的担忧。

我希望有人对已注释的部分提出建议。如果有一个比这更好的解决方案那么听起来很棒。

2 个答案:

答案 0 :(得分:1)

您无法检测到达到堆的限制(在运行时AFAIK无法获得占用堆的大小)

这就是我的所作所为。

我有一个listView并检测随时显示的图像数量(可见行|列)。添加新位图后,我会检查适配器,任何imageview都不会显示哪些缓存图像。如果我找到一个或多个i .recycle()它们。当我需要重新加载图像(我已经存储到手机的内存缓存)时,我不仅检查缓存中是否存在该图像,还检查位图是否被回收。 如果是再循环我重新编码它,否则如果没有我再次下载它。 这是最安全的操作。我还根据显示的位置缩小图像比例。 例如,如果我有200x200的图像,而imageView只有20x20,那么我会将图像缩小10次。

这样android会处理我在其上显示的evey单个图像。这就是回收位图,以及android回收imageViews本身的保存方式。

您必须知道当前有多少位图可见,以便您回收其余位图。

另外一个方便的技巧是当您对图像进行编码时(首先必须将其下载到缓存中)使用fileDescriptor进行编码

BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
o2.inPurgeable = true;
o2.inTempStorage = new byte[16 * 1024];
o2.inDither = true;
o2.inInputShareable = true; 

FileInputStream fs = null;
try {
    fs = new FileInputStream(f);
    } catch (FileNotFoundException e) {
   e.printStackTrace();
}

if (fs != null) {
    Bitmap b = BitmapFactory.decodeFileDescriptor(fs.getFD(),null, o2);
  }

但如果你做的一切都正确,你就不需要fileDescriptor(谁比较慢)

答案 1 :(得分:1)

如果您希望能够让缓存增长基本上无限制地达到VM堆的限制,您可以使用像SoftReference集合这样的东西到位图。

http://developer.android.com/reference/java/lang/ref/SoftReference.html

您可能还希望在活动onLowMemory()中实现,以便在您希望拥有如此大的缓存时也能很好地使用系统。