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
- Android LruCache图片缓存使用(一)
- Android LruCache图片缓存使用(二)
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- Android使用 LruCache 缓存图片
- ShellExecute, WinExec, CreateProcess区别
- 一些css小用法总结
- 第十二周 项目四 (2) 利用遍历思想求解图问题
- 第十三周项目4-Floyd算法验证
- 项目4 -- 每对顶点之间的最短路径
- Android LruCache图片缓存使用(一)
- 第十二周 项目4-利用遍历思想求解图问题(5)
- 选择排序
- 网络舆情分析技术 读书笔记1
- QT中QFileDialog的使用
- 第八周 字符串加密
- 文章标题
- 【第11周 项目1 - 二叉树算法验证(1)层次遍历算法的验证】
- 对linux 多路复用Epoll模型的水平出发模式和边缘触发模式的理解