2012-02-29 13 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

、(0)、それは自動的にあなたのためのダウンアイテムの残りの部分をシフトしていますか? –

+0

javadocによれば、それは... – assylias

+0

本当にアイテムが本当に削除されていることを確認するためにマップから削除した後に再びサイズを記録する価値がありますか? – assylias

答えて

2

いくつかの問題があります。

まず、cachedBitmapUrlsOrderListです。同じビットマップが複数回要求された場合はどうなりますか?リストに重複したURLがたくさんある。したがって、最初に制限に達すると、リストとマップからURLが削除されます。 同じURLがまだリストにあり、一致するマップエントリはではありません。したがって、リストから同じURLを削除しようとすると、ではなく、がマップから削除され、マップが拡大します。

addBitmapToCache()の先頭で、URLが既にキャッシュされている場合は、bitmapCache.containsKey(url)でチェックしてください。その場合、マップを変更する必要はありません。このエントリが最新のものとして記憶されていることを確認してください。

また、リストをユニーク値のコレクションに変更してください。おそらくタイムスタンプへのURLのマップ、またはSet。 (私はあなたに決めるつもりです)

また、get()size()メソッドも同期する必要があります。

get()は、検索されたエントリのタイムスタンプを更新して最新のものにする必要があります。

+1

なぜ成長しているのですが、map.containsKey(url)をチェックするキャッシュに追加メソッドの先頭に行を追加するのが最も簡単なのですか? –

+0

華麗な、ありがとう!完全に意味をなさない –

+0

@ cotton.mはい、私の答えにそれを加えました。ありがとう。 –

2

さらに、グラハムの答えがclearCacheに電話された場合、cachedBitmapUrlsOrderはクリアされません。あなたの次の時間が限界に達したときですから、ここで何を削除されることはありません:あなたは.removeを行う際

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

もうひとつ大きなキャッチ。明らかに、私にとってはDeveloper 101に戻っています。 –