LruCache 缓存

来源:互联网 发布:淘宝店铺注册流程 编辑:程序博客网 时间:2024/04/27 22:33
内存缓存(LruCache):
系统提供的LruCache类是非常适合用作缓存Bitmap任务的,
它将最近被引用到的对象存储在一个强引用的LinkedHashMap中,并且在缓存超过了指定大小之后将最近不常使用的对象释放掉。
注意:以前有一个非常流行的内存缓存实现是SoftReference(软引用)或者WeakReference(弱引用)的Bitmap缓存方案,
然而现在已经不推荐使用了。自Android2.3版本(API Level 9)开始,垃圾回收器更着重于对软/弱引用的回收,这使得上述的方案相当无效。

http://developer.android.com/reference/android/util/LruCache.html

/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.util;import java.util.LinkedHashMap;import java.util.Map;/** * Cache保存一个强引用来限制内容数量,每当Item被访问的时候,此Item就会移动到队列的头部。 * 当cache已满的时候加入新的item时,在队列尾部的item会被回收。 * 如果你cache的某个值需要明确释放,重写entryRemoved() * 如果key相对应的item丢掉啦,重写create().这简化了调用代码,即使丢失了也总会返回 * 默认cache大小是测量的item的数量,重写sizeof计算不同item的 *  大小。 *   int cacheSize = 4 * 1024 * 1024; // 4MiB  *   LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {  *       protected int sizeOf(String key, Bitmap value) {  *           return value.getByteCount();  *       }  *   }} *   不允许key或者value为null *   当get(),put(),remove()返回值为null时,key相应的项不在cache中 */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); // LinkedHashMap的初始化放在构造器中,                                                            //这里将LinkedHashMap的accessOrder设置为true,为插入顺序,默认是访问顺序    }    /**     * Sets the size of the cache.     * @param maxSize The new maximum size.     *     * @hide     */    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返回相应的item,或者创建返回相应的item。相应的item会移动到队列的头部,     * 如果item的value没有被cache或者不能被创建,则返回null。     */    public final V get(K key) {        if (key == null) { //不允许空键              throw new NullPointerException("key == null");        }        V mapValue;        synchronized (this) {            mapValue = map.get(key);//调用LinkedHashMap的get方法              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.         * 如果丢失了就试图创建一个item         */        V createdValue = create(key);        if (createdValue == null) {            return null;        }        synchronized (this) {            createCount++; //如果创建成功,那么create次数加1              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}.     */    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);//统计放入的值的大小,然后增加size的记录值              previous = map.put(key, value);//把新值放入缓存map中,然后获得旧值              if (previous != null) { //旧值不为空,由于替换了旧值,所以需要把缓存数据总大小减去这个旧值的大小                    size -= safeSizeOf(key, previous);            }        }        //还要调用entryRemoved()方法来让子类去处理不用的旧值previous,可能按照自己的方式去释放它。          //当然了,子类也可以不实现这个方法。          if (previous != null) {            entryRemoved(false, key, previous, value);        }        trimToSize(maxSize);        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.     把最少访问的老数据删除,直到总数据大小在上限的范围之内.      数据上限. 值可能是-1,这样就会删除所有的缓存数据.     */    public void trimToSize(int maxSize) {        while (true) { //不断删除linkedHashMap头部entry,也就是最近最少访问的条目,直到size小于最大容量              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) { //直到容量小于最大容量为止                      break;                }                Map.Entry<K, V> toEvict = map.eldest(); //获取最少访问的entry                if (toEvict == null) {                    break;                }                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}.     */    public final V remove(K key) {        if (key == null) {            throw new NullPointerException("key == null");        }        V previous;        synchronized (this) {            previous = map.remove(key);//调用LinkedHashMap的remove方法              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}.     */    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.     */    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.     * 这个方法用于计算每个条目的大小,子类必须得复写这个类。     */    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);    }}

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 c1升b2考不过怎么办 b2驾照扣了1分怎么办 红绿色盲驾考怎么办 驾驶证忘带被交警查了怎么办 车子被扣45分怎么办 驾照被扣在外省交警支队怎么办 从渭南把驾照转到西安怎么办 a1a2驾驶证扣3分怎么办 车辆累计扣12分怎么办 驾照扣了40分怎么办 驾驶证扣了30分怎么办 b2驾照逾期未审怎么办 c1实习期扣6分怎么办 车子累计扣30分怎么办 实习期间扣满12分怎么办 新手驾照扣6分怎么办 a2驾驶证逾期未审验怎么办 c1驾照扣了6分怎么办 b1驾照被扣12分怎么办 b2驾驶本扣分了怎么办 驾驶本扣9分后怎么办 b1照扣12分怎么办 b2扣了15分怎么办 b2有扣分未年审怎么办 b2驾驶证扣4分怎么办 b2驾驶证扣10分怎么办 刚发驾驶证照片太丑想换怎么办! 考驾照时户口变更怎么办 驾照年审色盲未过怎么办 考驾驶证互联网注册号码怎么办 驾驶证体检视力不过关怎么办 六年驾照满了怎么办 驾照扣了40多分怎么办 一个驾照扣24分怎么办 南昌电动车牌照丢了怎么办 上海餐饮工作人员怎么办健康证 房产过户没有遗嘱公证怎么办 在外地被扣12分怎么办 公务员体检视力不过关怎么办弱视 身份证被盗用注册公司怎么办 驾照分卖了12分怎么办