LruCache

package android.support.v4.util;

public class LruCache<K, V> {
    private final LinkedHashMap<K, V> map;//数据结构
    private int size;//已经存储的大小
    private int maxSize;//规定的最大存储空间

    private int putCount;//put的次数
    private int createCount;//create的次数
    private int evictionCount; //回收的次数
    private int hitCount;//命中的次数
    private int missCount; //丢失的次数

    public LruCache(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        this.maxSize = maxSize;
        //第3个参数
        //false: 基于插入顺序     true:  基于访问顺序(从最少到最多) 
        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
    }

  //重新设置最大存储空间
    public void resize(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        synchronized (this) {
            this.maxSize = maxSize;
        }
        trimToSize(maxSize);
    }

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

        V mapValue;
        synchronized (this) {
            mapValue = map.get(key);
            //如果map中存在值,直接返回
            if (mapValue != null) {
                hitCount++;
                return mapValue;
            }
            missCount++;
        }

        //map中不存在,可重写create方法,根据key,创建一个值
        V createdValue = create(key);
        if (createdValue == null) {
            return null;
        }

        synchronized (this) {
            createCount++;
            mapValue = map.put(key, createdValue);
            //create方法可能会执行很长时间,导致create执行完后,map发生了改变,key对应的value已经存在,这时舍弃这一次put
            if (mapValue != null) {
                // There was a conflict so undo that last put
                map.put(key, mapValue);
            } else {
                //更新当前存储的size大小
                size += safeSizeOf(key, createdValue);
            }
        }

        if (mapValue != null) {
            //子类重写此方法,被告知有一个旧值被废弃了
            entryRemoved(false, key, createdValue, mapValue);
            return mapValue;
        } else {
           //检测存储的大小是否超出
            trimToSize(maxSize);
            return createdValue;
        }
    }

    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;
    }

    //检测存储的大小是否超出
    public void trimToSize(int maxSize) {
        while (true) {
            K key;
            V value;
            synchronized (this) {
                if (size < 0 || (map.isEmpty() && size != 0)) {
                    throw new IllegalStateException(getClass().getName()
                            + ".sizeOf() is reporting inconsistent results!");
                }
                if (size <= maxSize || map.isEmpty()) {
                    break;
                }
                //将最近访问最少的这个值删除,
                //在android.util下的Lrucache实现代码如下:
                //Map.Entry<K, V> toEvict = map.eldest();
                //android.support.v4.util的实现如下:
                Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
                key = toEvict.getKey();
                value = toEvict.getValue();
               //如果当前size超过预设的最大值,则将最近访问最少的这个值删除,同时更新size大小
                map.remove(key);
                size -= safeSizeOf(key, value);
                evictionCount++;
            }
            //有值要移除,子类可重写此方法来接收
            entryRemoved(true, key, value, null);
        }
    }

    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;
    }

    //有值要移除,子类可重写此方法来接收,第一个参数true表示是因为存储满了而要回收的
    protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}

   //当要取的值不存在时,子类可重写此方法创建一个
    protected V create(K key) {
        return null;
    }

   //确保每一个value的大小不能小于0
    private int safeSizeOf(K key, V value) {
        int result = sizeOf(key, value);
        if (result < 0) {
            throw new IllegalStateException("Negative size: " + key + "=" + value);
        }
        return result;
    }

   //子类要重写此方法返回每一个value的大小,如果缓存的是图片,则要返回每张图片的大小
    protected int sizeOf(K key, V value) {
        return 1;
    }

    //清空缓存
    public final void evictAll() {
        trimToSize(-1); // -1 will evict 0-sized elements
    }

    public synchronized final int size() {
        return size;
    }

    public synchronized final int maxSize() {
        return maxSize;
    }

    public synchronized final int hitCount() {
        return hitCount;
    }

    public synchronized final int missCount() {
        return missCount;
    }

    public synchronized final int createCount() {
        return createCount;
    }

    public synchronized final int putCount() {
        return putCount;
    }

    public synchronized final int evictionCount() {
        return evictionCount;
    }

   //返回当前存储map的快照
    public synchronized final Map<K, V> snapshot() {
        return new LinkedHashMap<K, V>(map);
    }

    @Override 
    public synchronized final String toString() {
        int accesses = hitCount + missCount;
        int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
        return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
                maxSize, hitCount, missCount, hitPercent);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值