Android LruCache图片缓存使用(一)

来源:互联网 发布:王者荣耀天魔缭乱优化 编辑:程序博客网 时间:2024/05/16 11:44

LruCache我想对于做Android的人来说肯定是不会陌生的,在各种用到大量加载图片的地方就能看的这个类的身影,各大图片框架里面都有用到LruCache。最近项目一阶段的活已经做完了,发现自己好久没学习了,所以随便写点东西使自己学习学习。

LruCache是Android中专门用来做图片缓存处理的,它有一个特点,当图片达到了预先设定的值的时候,那么最近使用次数最少的图片就会被回收释放掉。LruCache位于android.support.v4.util这个包里面,下面我们来简单分析分析它的源码:

/** * Static library version of {@link android.util.LruCache}. Used to write apps * that run on API levels prior to 12. When running on API level 12 or above, * this implementation is still used; it does not try to switch to the * framework's implementation. See the framework SDK documentation for a class * overview. */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;                  //put的次数    private int createCount;               //create的次数    private int evictionCount;             //回收次数    private int hitCount;                  //命中次数    private int missCount;                 //丢失次数    /**     * @param maxSize for caches that do not override {@link #sizeOf}, this is     *     the maximum number of entries in the cache. For all other caches,     *     this is the maximum sum of the sizes of the entries in this cache. //设置缓存中最大存储量     */    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);    }    /**     * Sets the size of the cache. //设置缓存的大小     *     * @param maxSize The new maximum size.     */    public void resize(int maxSize) {        if (maxSize <= 0) {            throw new IllegalArgumentException("maxSize <= 0");        }        synchronized (this) {            this.maxSize = maxSize;        }        trimToSize(maxSize);    }    /**     * Returns the value for {@code key} if it exists in the cache or can be     * created by {@code #create}. If a value was returned, it is moved to the     * head of the queue. This returns null if a value is not cached and cannot     * be created.     */     //通过key返回相应的值,或者创建相应的值。如果该值有被返回则将其移动到队列的头部     //如果该值返回为null,则将不会被创建和缓存起来。    public final V get(K key) {        if (key == null) {            throw new NullPointerException("key == null");        }        V mapValue;        synchronized (this) {            mapValue = map.get(key);            if (mapValue != null) {                hitCount++; //命中                return mapValue;            }            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.         */        V createdValue = create(key);        if (createdValue == null) {            return null;        }        synchronized (this) {            createCount++;            mapValue = map.put(key, createdValue);            if (mapValue != null) {                // There was a conflict so undo that last put                map.put(key, mapValue);            } else {                size += safeSizeOf(key, createdValue);            }        }        if (mapValue != null) {            entryRemoved(false, key, createdValue, mapValue);            return mapValue;        } else {            trimToSize(maxSize);            return createdValue;        }    }    /**     * Caches {@code value} for {@code key}. The value is moved to the head of     * the queue.     *     * @return the previous value mapped by {@code key}.     */     // 通过key缓存的value,这个value将会被移动到队列的头部    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) {//排除之前已经插入了相同的key                size -= safeSizeOf(key, previous);//那么减去该entry的容量,因为发生覆盖            }        }        if (previous != null) {            entryRemoved(false, key, previous, value);//这个方法默认空实现        }        trimToSize(maxSize);//若容量超过maxsize,将会删除最近很少访问的entry        return previous;    }    /**     * Remove the eldest entries until the total of remaining entries is at or     * below the requested size.     *     * @param maxSize the maximum size of the cache before returning. May be -1     *            to evict even 0-sized elements.     */     //移除最早或最老的条目(最少使用的),直到当前缓存的大小数量不大于请求的大小(maxSize)    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;                }                Map.Entry<K, V> toEvict = map.entrySet().iterator().next();                key = toEvict.getKey();                value = toEvict.getValue();                map.remove(key);//删除最少访问的entry                size -= safeSizeOf(key, value);                evictionCount++;            }            entryRemoved(true, key, value, null);        }    }    /**     * Removes the entry for {@code key} if it exists.     *     * @return the previous value mapped by {@code key}.     */     //移除缓存中存在key相对应的值    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;    }    /**     * Called for entries that have been evicted or removed. This method is     * invoked when a value is evicted to make space, removed by a call to     * {@link #remove}, or replaced by a call to {@link #put}. The default     * implementation does nothing.     *       * <p>The method is called without synchronization: other threads may     * access the cache while this method is executing.     *     * @param evicted true if the entry is being removed to make space, false     *     if the removal was caused by a {@link #put} or {@link #remove}.     * @param newValue the new value for {@code key}, if it exists. If non-null,     *     this removal was caused by a {@link #put}. Otherwise it was caused by     *     an eviction or a {@link #remove}.     */     // 使用的条目被回收或删除时调用,该方法当value被回收释放存储空间时被remove调用,     // 或者替换item值时被put调用。默认什么都没做,evicted:true为释放空间;false为put或remove导致    protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}    /**     * Called after a cache miss to compute a value for the corresponding key.     * Returns the computed value or null if no value can be computed. The     * default implementation returns null.     *     * <p>The method is called without synchronization: other threads may     * access the cache while this method is executing.     *     * <p>If a value for {@code key} exists in the cache when this method     * returns, the created value will be released with {@link #entryRemoved}     * and discarded. This can occur when multiple threads request the same key     * at the same time (causing multiple values to be created), or when one     * thread calls {@link #put} while another is creating a value for the same     * key.     */     //某个key对应的item丢失时,或者同一个key值时(一个LruCache只能存储一个相同的key)调用     //避免多线程操作同一个key    protected V create(K key) {        return null;    }    private int safeSizeOf(K key, V value) {        int result = sizeOf(key, value);        if (result < 0) {            throw new IllegalStateException("Negative size: " + key + "=" + value);        }        return result;    }    /**     * Returns the size of the entry for {@code key} and {@code value} in     * user-defined units.  The default implementation returns 1 so that size     * is the number of entries and max size is the maximum number of entries.     *     * <p>An entry's size must not change while it is in the cache.     */    //返回用户定义的item的大小,默认返回1代表item的数量,最大size就是最大item值    protected int sizeOf(K key, V value) {        return 1;    }    /**     * Clear the cache, calling {@link #entryRemoved} on each removed entry.     */    //清空队列中的缓存    public final void evictAll() {        trimToSize(-1); // -1 will evict 0-sized elements    }    /**     * For caches that do not override {@link #sizeOf}, this returns the number     * of entries in the cache. For all other caches, this returns the sum of     * the sizes of the entries in this cache.     */    public synchronized final int size() {        return size;    }    /**     * For caches that do not override {@link #sizeOf}, this returns the maximum     * number of entries in the cache. For all other caches, this returns the     * maximum sum of the sizes of the entries in this cache.     */    public synchronized final int maxSize() {        return maxSize;    }    /**     * Returns the number of times {@link #get} returned a value that was     * already present in the cache.     */    public synchronized final int hitCount() {        return hitCount;    }    /**     * Returns the number of times {@link #get} returned null or required a new     * value to be created.     */    public synchronized final int missCount() {        return missCount;    }    /**     * Returns the number of times {@link #create(Object)} returned a value.     */    public synchronized final int createCount() {        return createCount;    }    /**     * Returns the number of times {@link #put} was called.     */    public synchronized final int putCount() {        return putCount;    }    /**     * Returns the number of values that have been evicted.     */    //这里返回被回收的数量    public synchronized final int evictionCount() {        return evictionCount;    }    /**     * Returns a copy of the current contents of the cache, ordered from least     * recently accessed to most recently accessed.     */     //返回一个当前的所有缓存的副本条目(从最近最少访问到最多访问)    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);    }}

通过上面简单的分析,我们基本上可以知道:
1.LruCache封装了LinkedHashMap(双向链表),提供了LRU(最近最少使用的缓存)功能。
2.LruCache中不允许空键值。
3.LruCache中不存储重复的键值。
4.LruCache中各处都加了synchronized,它的线程是安全的。
5.LruCache通过trimToSize方法自动删除最近最少访问的键值对。
6.继承LruCache时,必须要复写sizeof()方法,用于计算每个条目的大小。(注意)

源码解析就暂时到这,后面再来讲诉如何使用LruCache进行图片缓存…
pass:上面解析有错误的地方欢迎指出,么么哒!

2 0
原创粉丝点击