2012-02-29 83 views
3

我被这个彻底难倒了。我有一个静态类,它管理下载的位图图像的缓存。这个类可以被多个线程访问,并可以进行并发访问。下面是执行:为什么我的缓存机制无法按预期工作?

public class BitmapCache { 
    private static final int MAX_NUMBER_BITMAPS_TO_CACHE = 30; 
    private static Map<String, Bitmap> bitmapCache = new HashMap<String, Bitmap>(); 
    private static List<String> cachedBitmapUrlsOrder = new ArrayList<String>(); 

    private BitmapCache(){} 

    public static synchronized void addBitmapToCache(String url, Bitmap bitmap) { 
     if (bitmapCache.size() >= MAX_NUMBER_BITMAPS_TO_CACHE) { 
      Log.i("MyApp", "Max cache size reached. Removing oldest bitmap. Size = " + bitmapCache.size()); 
      String oldestUrl = cachedBitmapUrlsOrder.remove(0); 
      bitmapCache.remove(oldestUrl); 
     } 
     bitmapCache.put(url, bitmap); 
     cachedBitmapUrlsOrder.add(url); 
    } 

    public static int size() { 
     return bitmapCache.size(); 
    } 

    public static Bitmap get(String url) { 
     return bitmapCache.get(url); 
    } 

    public synchronized static void clearCache() { 
     bitmapCache.clear(); 
    } 
} 

我想,这样当达到最大缓存大小(经常发生的事情)最古老的位图从缓存中移除来实现滚动缓存。运行我的应用程序提供了以下的输出:

02-29 23:00:26.590: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 30 
02-29 23:00:26.600: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 30 
02-29 23:00:26.720: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 30 
02-29 23:00:26.790: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 30 
02-29 23:00:26.820: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 31 
02-29 23:00:26.850: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 31 
02-29 23:00:27.050: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 32 
02-29 23:00:27.070: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 32 
02-29 23:00:27.100: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 33 
02-29 23:00:27.130: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 34 
02-29 23:00:27.170: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 35 
02-29 23:00:27.210: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 35 
02-29 23:00:27.330: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 35 
02-29 23:00:27.360: I/MyApp(10789): Max cache size reached. Removing oldest bitmap. Size = 35 

代码正确开始记录“达到最大缓存大小”当高速缓存大小达到30和在那里停留数执行。但是它奇怪地开始增加到35点。在这一点上,它保持在那里数百个输出。我无法让它增加到35以上。

我的实现有什么问题?鉴于addBitmapToCache方法是同步的,我很难理解缓存大小如何超过最大集。

+0

在java的,当你卸下摆臂(0),它会自动将其余项目下移的吗? – 2012-02-29 23:21:01

+0

根据javadoc它确实... – assylias 2012-02-29 23:21:37

+0

也许值得从地图中删除后再次记录大小,以确保一个项目已被删除? – assylias 2012-02-29 23:23:00

回答

2

有几个问题。首先,cachedBitmapUrlsOrderList。如果多次请求相同的位图,会发生什么?您会在列表中看到大量重复的网址。因此,当您第一次达到上限时,您会从列表中和地图中删除一个网址。 但是相同的URL仍在列表中,没有匹配的映射条目。因此,随后尝试从列表中删除相同的URL将从不是删除任何地图,并且地图将增长。

您可以通过在addBitmapToCache()开头检查URL是否已被缓存来避免这种情况,其中bitmapCache.containsKey(url)。如果是这样,你不需要修改地图;只要确保这个条目被记住为最新的。

或者,将列表更改为唯一值的集合;可能是一个URL到时间戳的映射,或者一个Set。 (我会让你决定。)

此外,get()size()方法也应该被同步。

get()应该更新检索到的条目的时间戳,以便它成为最近的。

+1

同意它为什么增长,但不是最简单的方法就是在添加到缓存方法的开始处添加一行来检查map.containsKey(url)? – 2012-02-29 23:25:55

+0

辉煌,非常感谢!总体感觉。 – 2012-02-29 23:29:50

+0

@ cotton.m是的,加到我的答案。谢谢。 – 2012-02-29 23:31:04

2

另外格雷厄姆的回答,如果打电话给clearCachecachedBitmapUrlsOrder没有被清除。所以,当你下一次达到一个极限,你就不会在这里消除任何:

String oldestUrl = cachedBitmapUrlsOrder.remove(0); 
bitmapCache.remove(oldestUrl); // bitmapCache does not have such key 
+0

另一个伟大的捕获。显然,它回到了Developer 101。 – 2012-02-29 23:31:11

相关问题