可以访问所有现有项目的缓存

时间:2013-10-22 04:48:54

标签: java android caching soft-references

我有一个系统,其中对象(为了这个问题的目的,它们是不可变的)是基于请求对象创建的(可以像url或long一样简单)。它们是使用工厂方法创建的,而不是new

如果请求的对象已经存在,那么如果我们可以获得对现有实例的引用,则可以更有效地请求新对象。

为此,我创建了一个名为UniversalCache<K, V>的课程,因为此时缺少一个更好的名字。它有一个LruCache,以便保留X个强引用,并HashMap<K, SoftReference<V> >跟踪所有可能仍然通过系统中的其他强引用保持活动的对象(我是不依赖于SoftReference保持对象不被GC化。)

当创建一个尚未在缓存中的新对象时,它将与其密钥一起添加到缓存中。要在缓存中搜索它,我使用密钥来获取引用并检查它是否仍然具有对象的引用。

我遇到的问题是如何在对象被垃圾收集后删除这些键/引用对。我不想通过整个HashMap搜索poll返回null的引用。由于指示对象并不总是可用,因此我无法使用它来获取或生成回键。因此,我正在扩展SoftReference以存储密钥,并使用它从HashMap中删除该对。这是一个好主意吗?我有一个KeyedSoftReference<K,Rt>,其中包含与缓存相同类型K的附加字段(和Rt最终与V相同)。< / p>

特别是我想知道在哪里处理ReferenceQueue(目前在get中),以及如何投射我从ReferenceQueue.poll()得到的对象。

这是我到目前为止的代码:

    package com.frozenkoi.oss;

    import java.lang.ref.Reference;
    import java.lang.ref.ReferenceQueue;
    import java.lang.ref.SoftReference;
    import java.util.HashMap;

    import android.util.LruCache;

    public class UniversalCache<K, V> {
            private final LruCache<K, V> mStrongCache;
            private final HashMap<K, KeyedSoftReference<K, V> > mSoftCache;
            private final ReferenceQueue<V> mRefQueue;

            private static class KeyedSoftReference<K, Rt> extends SoftReference<Rt>
            {
                    private final K mKey;
                    public KeyedSoftReference(K key, Rt r, ReferenceQueue<? super Rt> q)
                    {
                            super(r, q);
                            mKey = key;
                    }

                    public K getKey()
                    {
                            return mKey;
                    }
            }

            public UniversalCache(int strongCacheMaxItemCount)
            {
                    mStrongCache = new LruCache<K, V>(strongCacheMaxItemCount);
                    mSoftCache = new HashMap<K, KeyedSoftReference<K, V> >();
                    mRefQueue = new ReferenceQueue<V>();
            }

            private void solidify(K key, V value)
            {
                    mStrongCache.put(key, value);
            }

            public void put(K key, V value)
            {
                    solidify(key, value);
                    mSoftCache.put(key, new KeyedSoftReference<K, V>(key, value, mRefQueue));
            }

            public V get(K key)
            {
                    //if it's in Strong container, must also be in soft.
                    //just check in one of them
                    KeyedSoftReference<K,? extends V> tempRef = mSoftCache.get(key);
                    final V tempVal = (null!=tempRef)?tempRef.get():null;

                    V retVal = null;

                    if (null == tempVal)
                    {
                            mSoftCache.remove(key);
                            retVal = tempVal;
                    }
                    else
                    {
                            //if found in LruCache container, must be also in Soft one
                            solidify(key, tempVal);
                            retVal = tempVal;
                    }

                    //remove expired entries
                    while (null != (tempRef = (KeyedSoftReference<K,V>)mRefQueue.poll()))       //Cast
                    {
                            //how to get key from val?
                            K tempKey = tempRef.getKey();
                            mSoftCache.remove(tempKey);
                    }

                    return retVal;
            }

    }

0 个答案:

没有答案