Android LRUCache

 17 package android.util;
 18
 19 import java.util.LinkedHashMap;
 20 import java.util.Map;
 21
 22 /**
 23  * A cache that holds strong references to a limited number of values. Each time
 24  * a value is accessed, it is moved to the head of a queue. When a value is
 25  * added to a full cache, the value at the end of that queue is evicted and may
 26  * become eligible for garbage collection. 一个cache缓冲区,维护有限个值的强引用。当一个值被命中时,它被移到队列的头部???确定有移动么当一个值被加入一个已满的cache中时,队列最后一个值被舍弃。可能会被垃圾回收 28  * <p>If your cached values hold resources that need to be explicitly released,
 29  * override {@link #entryRemoved}.如果你缓存的值中有必须被释放的资源,需要override  entryRemoved方法 31  * <p>If a cache miss should be computed on demand for the corresponding keys,
 32  * override {@link #create}. This simplifies the calling code, allowing it to
 33  * assume a value will always be returned, even when there‘s a cache miss.如果一次cache未命中时,同样需要返回。 需要override create()方法。这使调用简化:不管是不是命中,都返回一个值。

因为当前的create方法返回的是个null。当你没get到的时候,会调用create方法。在当前情况下,返回null会直接return null。不会往后执行之后的创建键值对,并返回的操作。

但是如果你重写了create(),使其返回的不是null,则后边的操作会执行。调用get(key),value值被返回。 35  * <p>By default, the cache size is measured in the number of entries. Override
 36  * {@link #sizeOf} to size the cache in different units. For example, this cache
 37  * is limited to 4MiB of bitmaps:默认情况下,一个cache的大小,是以实体的个数来衡量的。因为当前的sizeOf() 方法返回的是1,也就是每个entry大小是1你可以override  sizeof方法,改变cache 的最小单元大小。例如,下边这个cache 限制为最大4MiB的bitmap cache每个单元的大小就不是1了,而是bitmap的大小。
 38  * <pre>   {@code
 39  *   int cacheSize = 4 * 1024 * 1024; // 4MiB
 40  *   LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
 41  *       protected int sizeOf(String key, Bitmap value) {
 42  *           return value.getByteCount();
 43  *       }
 44  *   }}</pre>
LRUCache类是线程安全的。多个cache操作时候。要synchronize这个cache

 46  * <p>This class is thread-safe. Perform multiple cache operations atomically by
 47  * synchronizing on the cache: <pre>   {@code
 48  *   synchronized (cache) {
 49  *     if (cache.get(key) == null) {
 50  *         cache.put(key, value);
 51  *     }
 52  *   }}</pre>
这个类不允许传入的key和value是空。get put remove返回null,代表这个key不再cache中

 54  * <p>This class does not allow null to be used as a key or value. A return
 55  * value of null from {@link #get}, {@link #put} or {@link #remove} is
 56  * unambiguous: the key was not in the cache.
 57  *
 58  * <p>This class appeared in Android 3.1 (Honeycomb MR1); it‘s available as part
 59  * of <a href="http://developer.android.com/sdk/compatibility-library.html">Android‘s
 60  * Support Package</a> for earlier releases.
 61  */
 62 public class LruCache<K, V> {
 63     private final LinkedHashMap<K, V> map;
 64
 65     /** Size of this cache in units. Not necessarily the number of elements. */
 66     private int size;
 67     private int maxSize;
 68
 69     private int putCount;
 70     private int createCount;
 71     private int evictionCount;
 72     private int hitCount;
 73     private int missCount;
 74
 75     /**
 76      * @param maxSize for caches that do not override {@link #sizeOf}, this is
 77      *     the maximum number of entries in the cache. For all other caches,
 78      *     this is the maximum sum of the sizes of the entries in this cache.
 79      */
 80     public LruCache(int maxSize) {
 81         if (maxSize <= 0) {
 82             throw new IllegalArgumentException("maxSize <= 0");
 83         }
 84         this.maxSize = maxSize;
 85         this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
 86     }
 87
 88     /**
 89      * Sets the size of the cache.
 90      * @param maxSize The new maximum size.
 91      *
 92      * @hide
 93      */
 94     public void resize(int maxSize) {
 95         if (maxSize <= 0) {
 96             throw new IllegalArgumentException("maxSize <= 0");
 97         }
 98
 99         synchronized (this) {
100             this.maxSize = maxSize;
101         }
102         trimToSize(maxSize);
103     }
104
105     /**
106      * Returns the value for {@code key} if it exists in the cache or can be
107      * created by {@code #create}. If a value was returned, it is moved to the
108      * head of the queue. This returns null if a value is not cached and cannot
109      * be created.
110      */
111     public final V get(K key) {
112         if (key == null) {
113             throw new NullPointerException("key == null");
114         }
115
116         V mapValue;
117         synchronized (this) {
118             mapValue = map.get(key);
119             if (mapValue != null) {
120                 hitCount++;
121                 return mapValue;
122             }
123             missCount++;
124         }
125
126         /*
127          * Attempt to create a value. This may take a long time, and the map
128          * may be different when create() returns. If a conflicting value was
129          * added to the map while create() was working, we leave that value in
130          * the map and release the created value.
131          */
132
133         V createdValue = create(key);
134         if (createdValue == null) {
135             return null;
136         }
137
138         synchronized (this) {
139             createCount++;
140             mapValue = map.put(key, createdValue);
141
142             if (mapValue != null) {
143                 // There was a conflict so undo that last put
144                 map.put(key, mapValue);
145             } else {
146                 size += safeSizeOf(key, createdValue);
147             }
148         }
149
150         if (mapValue != null) {
151             entryRemoved(false, key, createdValue, mapValue);
152             return mapValue;
153         } else {
154             trimToSize(maxSize);
155             return createdValue;
156         }
157     }
158
159     /**
160      * Caches {@code value} for {@code key}. The value is moved to the head of
161      * the queue.
162      *
163      * @return the previous value mapped by {@code key}.
164      */
165     public final V put(K key, V value) {
166         if (key == null || value == null) {
167             throw new NullPointerException("key == null || value == null");
168         }
169
170         V previous;
171         synchronized (this) {
172             putCount++;
173             size += safeSizeOf(key, value);
174             previous = map.put(key, value);
175             if (previous != null) {
176                 size -= safeSizeOf(key, previous);
177             }
178         }
179
180         if (previous != null) {
181             entryRemoved(false, key, previous, value);
182         }
183
184         trimToSize(maxSize);
185         return previous;
186     }
187
188     /**
189      * Remove the eldest entries until the total of remaining entries is at or
190      * below the requested size.
191      *
192      * @param maxSize the maximum size of the cache before returning. May be -1
193      *            to evict even 0-sized elements.
194      */
195     public void trimToSize(int maxSize) {
196         while (true) {
197             K key;
198             V value;
199             synchronized (this) {
200                 if (size < 0 || (map.isEmpty() && size != 0)) {
201                     throw new IllegalStateException(getClass().getName()
202                             + ".sizeOf() is reporting inconsistent results!");
203                 }
204
205                 if (size <= maxSize) {
206                     break;
207                 }
208
209                 Map.Entry<K, V> toEvict = map.eldest();
210                 if (toEvict == null) {
211                     break;
212                 }
213
214                 key = toEvict.getKey();
215                 value = toEvict.getValue();
216                 map.remove(key);
217                 size -= safeSizeOf(key, value);
218                 evictionCount++;
219             }
220
221             entryRemoved(true, key, value, null);
222         }
223     }
224
225     /**
226      * Removes the entry for {@code key} if it exists.
227      *
228      * @return the previous value mapped by {@code key}.
229      */
230     public final V remove(K key) {
231         if (key == null) {
232             throw new NullPointerException("key == null");
233         }
234
235         V previous;
236         synchronized (this) {
237             previous = map.remove(key);
238             if (previous != null) {
239                 size -= safeSizeOf(key, previous);
240             }
241         }
242
243         if (previous != null) {
244             entryRemoved(false, key, previous, null);
245         }
246
247         return previous;
248     }
249
250     /**
251      * Called for entries that have been evicted or removed. This method is
252      * invoked when a value is evicted to make space, removed by a call to
253      * {@link #remove}, or replaced by a call to {@link #put}. The default
254      * implementation does nothing.
255      *
256      * <p>The method is called without synchronization: other threads may
257      * access the cache while this method is executing.
258      *
259      * @param evicted true if the entry is being removed to make space, false
260      *     if the removal was caused by a {@link #put} or {@link #remove}.
261      * @param newValue the new value for {@code key}, if it exists. If non-null,
262      *     this removal was caused by a {@link #put}. Otherwise it was caused by
263      *     an eviction or a {@link #remove}.
264      */
265     protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
266
267     /**
268      * Called after a cache miss to compute a value for the corresponding key.
269      * Returns the computed value or null if no value can be computed. The
270      * default implementation returns null.
271      *
272      * <p>The method is called without synchronization: other threads may
273      * access the cache while this method is executing.
274      *
275      * <p>If a value for {@code key} exists in the cache when this method
276      * returns, the created value will be released with {@link #entryRemoved}
277      * and discarded. This can occur when multiple threads request the same key
278      * at the same time (causing multiple values to be created), or when one
279      * thread calls {@link #put} while another is creating a value for the same
280      * key.
281      */
282     protected V create(K key) {
283         return null;
284     }
285
286     private int safeSizeOf(K key, V value) {
287         int result = sizeOf(key, value);
288         if (result < 0) {
289             throw new IllegalStateException("Negative size: " + key + "=" + value);
290         }
291         return result;
292     }
293
294     /**
295      * Returns the size of the entry for {@code key} and {@code value} in
296      * user-defined units.  The default implementation returns 1 so that size
297      * is the number of entries and max size is the maximum number of entries.
298      *
299      * <p>An entry‘s size must not change while it is in the cache.
300      */
301     protected int sizeOf(K key, V value) {
302         return 1;
303     }
304
305     /**
306      * Clear the cache, calling {@link #entryRemoved} on each removed entry.
307      */
308     public final void evictAll() {
309         trimToSize(-1); // -1 will evict 0-sized elements
310     }
311
312     /**
313      * For caches that do not override {@link #sizeOf}, this returns the number
314      * of entries in the cache. For all other caches, this returns the sum of
315      * the sizes of the entries in this cache.
316      */
317     public synchronized final int size() {
318         return size;
319     }
320
321     /**
322      * For caches that do not override {@link #sizeOf}, this returns the maximum
323      * number of entries in the cache. For all other caches, this returns the
324      * maximum sum of the sizes of the entries in this cache.
325      */
326     public synchronized final int maxSize() {
327         return maxSize;
328     }
329
330     /**
331      * Returns the number of times {@link #get} returned a value that was
332      * already present in the cache.
333      */
334     public synchronized final int hitCount() {
335         return hitCount;
336     }
337
338     /**
339      * Returns the number of times {@link #get} returned null or required a new
340      * value to be created.
341      */
342     public synchronized final int missCount() {
343         return missCount;
344     }
345
346     /**
347      * Returns the number of times {@link #create(Object)} returned a value.
348      */
349     public synchronized final int createCount() {
350         return createCount;
351     }
352
353     /**
354      * Returns the number of times {@link #put} was called.
355      */
356     public synchronized final int putCount() {
357         return putCount;
358     }
359
360     /**
361      * Returns the number of values that have been evicted.
362      */
363     public synchronized final int evictionCount() {
364         return evictionCount;
365     }
366
367     /**
368      * Returns a copy of the current contents of the cache, ordered from least
369      * recently accessed to most recently accessed.
370      */
371     public synchronized final Map<K, V> snapshot() {
372         return new LinkedHashMap<K, V>(map);
373     }
374
375     @Override public synchronized final String toString() {
376         int accesses = hitCount + missCount;
377         int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
378         return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
379                 maxSize, hitCount, missCount, hitPercent);
380     }
381 }
时间: 2024-11-03 22:28:11

Android LRUCache的相关文章

Android LruCache 压缩图片 有效避免程序OOM

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9316683 本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工,英文好的朋友也可以直接去读原文. http://developer.android.com/training/displaying-bitmaps/index.html 压缩加载大图片 我们在编写Android程序的时候经常要用到许多图片,不同图片总是会有不同的形状.不同的大小,但在大多数情况下,这

Android LruCache究竟是什么

源码: /frameworks/base/core/java/android/util/LruCache.java 文件开篇注释如下: 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 valu

android LRUCache解析

LRU(Least Recently Used)最近最少使用算法 原理 缓存保存了一个强引用(Android 2.3开始,垃圾回收器更倾向于回收弱引用和软引用,软引用和弱引用变得不可靠,Android 3.0中,图片的数据会存储在本地的内存当中,因而无法用一种可预见的方式将其释放)限制值的数量. 每当值被访问的时候,它会被移动到队列的头部. 当缓存已满的时候加入新的值时,队列中最后的值会出队,可能被回收 LRUCache内部维护主要是通过LinkedHashMap实现 这是一个安全的线程,多线程

【转】Android LruCache源码介绍

本文来源:转载自: http://blog.csdn.net/linghu_java/article/details/8574102 package android.util; import java.util.LinkedHashMap; import java.util.Map; /** * A cache that holds strong references to a limited number of values. Each time * a value is accessed,

Android LruCache类分析

public class LurCache<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; // 回收的次数 priva

Android lrucache 实现与使用(Android内存优化)

什么是LruCache? LruCache实现原理是什么? 这两个问题其实可以作为一个问题来回答,知道了什么是 LruCache,就只然而然的知道 LruCache 的实现原理:Lru的全称是Least Recently Used ,近期最少使用的!所以我们可以推断出 LruCache 的实现原理:把近期最少使用的数据从缓存中移除,保留使用最频繁的数据,那具体代码要怎么实现呢,我们进入到源码中看看. LruCache源码分析 public class LruCache<K, V> { //缓存

Android ImageCache图片缓存,使用简单,支持预取,支持多种缓存算法,支持不同网络类型,扩展性强

本文主要介绍一个支持图片自动预取.支持多种缓存算法的图片缓存的使用及功能.图片较大需要SD卡保存情况推荐使用ImageSDCardCache. 与Android LruCache相比主要特性:(1).  使用简单   (2). 轻松获取及预取新图片  (3).  可选择多种缓存算法(FIFO.LIFO.LRU.MRU.LFU.MFU等13种)或自定义缓存算法   (4).  省流量性能佳(有且仅有一个线程获取图片)   (5).  支持不同类型网络处理  (6).  可根据系统配置初始化缓存 

【Java/Android性能优5】 Android ImageCache图片缓存,使用简单,支持预取,支持多种缓存算法,支持不同网络类型,扩展性强

本文转自:http://www.trinea.cn/android/android-imagecache/ 主要介绍一个支持图片自动预取.支持多种缓存算法.支持二级缓存.支持数据保存和恢复的图片缓存的使用.功能及网友反馈的常见问题解答. 与Android LruCache相比主要特性:(1). 使用简单  (2). 轻松获取及预取新图片  (3). 包含二级缓存  (4). 可选择多种缓存算法(FIFO.LIFO.LRU.MRU.LFU.MFU等 13种)或自定义缓存算法  (5). 可方便的保

【Java/Android性能优 6】Android 图片SD卡缓存 使用简单 支持预取 支持多种缓存算法 支持不同网络类型 支持序列化

本文转自:http://www.trinea.cn/android/android-imagesdcardcache/ 本文主要介绍一个支持图片自动预取.支持多种缓存算法.支持数据保存和恢复的图片Sd卡缓存的使用.功能及网友反馈的常见问题解答. 需要二级缓存或ListView和GridView图片加载请优先使用ImageCache. 与Android LruCache相比主要特性:(1). 使用简单  (2). 轻松获取及预取新图片  (3). 可选择多种缓存算法(FIFO.LIFO.LRU.M