通过上述的案例,我们已经知道了LruCache的使用方法。接下来,我们一步步的分析它的过程以及原理。

一、 LruCache的文档描述如下:

A cache that holds strong references to a limited number of values. Each time a value is accessed, it is moved to the head of a queue. When a value is added to a full cache, the value at the end of that queue is evicted and may become eligible for garbage collection.

翻译一下就是:

一个缓存,它拥有对有限数量值的强引用。 每次访问一个值时,它都会被移到队列头部。 
将值添加到完整缓存时,该队列末尾的值将被逐出,并可能有资格进行垃圾回收。

大白话翻译:

这个一个队列,是用来控制缓存的,它通过强引用数量来管理:每次访问一个缓存对象,该缓存对象就会移动到队列头部,如果缓存已经满了,还想进行缓存,该队列对象就会把末尾不常用的对象给回收掉,来为新缓存腾出空间!

二、 它的属性一方法说明如下:

public class LruCache<K, V> {
    private final LinkedHashMap<K, V> map;
    /** Size of this cache in units. Not necessarily the number of elements. */
    private int size;
    private int maxSize;

    private int putCount;
    private int createCount;
    private int evictionCount;
    private int hitCount;
    private int missCount;
}

文档上一些对LruCache方法的描述:

If your cached values hold resources that need to be explicitly released, override entryRemoved(boolean, K, V, V)

If a cache miss should be computed on demand for the corresponding keys, override create(K). This simplifies the calling code, allowing it to assume a value will always be returned, even when there's a cache miss.

By default, the cache size is measured in the number of entries. Override sizeOf(K, V) to size the cache in different units. For example, this cache is limited to 4MiB of bitmaps:

翻译一下:

如果您的缓存值保存需要显式释放的资源,请覆盖entryRemoved(布尔值,K,V,V)

如果需要为相应的键计算缓存未命中,请覆盖create(K)。 这简化了调用代码,允许它假定一个值总是会被返回,即使有一个缓存未命中。

默认情况下,高速缓存大小是根据条目数衡量的。 覆盖sizeOf(K,V)以不同单位调整缓存的大小。 例如,该缓存仅限于4MiB的位图:

三、 LruCache只有一个构造方法,LruCache(int maxSize)代码如下:初始化一个LinkedHashMap

public LruCache(int maxSize) {
    if (maxSize <= 0) {
        throw new IllegalArgumentException("maxSize <= 0");
    }
    this.maxSize = maxSize;
    this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}

四、 LruCache的put方法是把内容放入到缓存中去,代码如下:

public final V put(K key, V value) {
    if (key == null || value == null) {
        throw new NullPointerException("key == null || value == null");
    }

    V previous;
    synchronized (this) {
        putCount++;
        size += safeSizeOf(key, value);
        previous = map.put(key, value);
        if (previous != null) {
            size -= safeSizeOf(key, previous);
        }
    }

    if (previous != null) {
        entryRemoved(false, key, previous, value);
    }

    trimToSize(maxSize);
    return previous;
}

其中safeSizeOf方法,是计算LruCache的已经缓存的大小,以下的sizeOf(默认返回1)方法是我们要重写的。

private int safeSizeOf(K key, V value) {
    int result = sizeOf(key, value);
    if (result < 0) {
        throw new IllegalStateException("Negative size: " + key + "=" + value);
    }
    return result;
}

我们要重写sizeOf方法:

protected int sizeOf(K key, V value) {
    return 1;
}

五、 LruCache的get方法是从缓存中去取得内容,代码如下:

public final V get(K key) {
    if (key == null) {
        throw new NullPointerException("key == null");
    }

    V mapValue;
    synchronized (this) {     // 如果根据相应的key得到value,就增加一次命中hitCount,并且返回结果
        mapValue = map.get(key);
        if (mapValue != null) {
            hitCount++;
            return mapValue;
        }     // 否则增加一次missCount
        missCount++;
    }

    /*
     * Attempt to create a value. This may take a long time, and the map
     * may be different when create() returns. If a conflicting value was
     * added to the map while create() was working, we leave that value in
     * the map and release the created value.
     */
  // 试图根据这个key,创建一个value。这里的create(key)默认是返回null,当然这个方法是可以重写的
    V createdValue = create(key);
    if (createdValue == null) {
        return null;
    }

    synchronized (this) {
        createCount++;     // 如果我们重写了create(key)方法而且返回值不为空,那么将上述的key与这个返回值写入到map当中
        mapValue = map.put(key, createdValue);

        if (mapValue != null) {
            // There was a conflict so undo that last put       // 方法放入最后put的key,value值            map.put(key, mapValue);
        } else {
            size += safeSizeOf(key, createdValue);
        }
    }

    if (mapValue != null) {     // 这个方法也可以重写
        entryRemoved(false, key, createdValue, mapValue);
        return mapValue;
    } else {
        trimToSize(maxSize);
        return createdValue;
    }
}

六、 LruCache的remove方法是从缓存中去删除内容,并更新已经缓存的大小,代码如下:

public final V remove(K key) {
    if (key == null) {
        throw new NullPointerException("key == null");
    }

    V previous;
    synchronized (this) {
        previous = map.remove(key);
        if (previous != null) {
            size -= safeSizeOf(key, previous);
        }
    }

    if (previous != null) {
        entryRemoved(false, key, previous, null);
    }

    return previous;
}

results matching ""

    No results matching ""