android:LruCache缓存小结
LruCache以键值对的形式,初始化时,需要设置缓存的大小K,超过这个大小的数据将会被清除。注意:清除的数据,是那些被先加入的数据。LruCache内部的数据结构是LinkedHashMap存储的。这样,LruCache就达到了缓存最近put的K个数据。
使用:
[code]
int cacheSize = 4 * 1024 * 1024; // 4MiB LruCache bitmapCache = new LruCache(cacheSize) { protected int sizeOf(String key, Bitmap value) { return value.getByteCount(); }}
注意,缓存不同的数据,需要重写sizeOf方法。比如,上面缓存的是图片。本质上,这些数据都是存储在内存中的,因此,cacheSize不易过大。
LruCache源代码:
import java.util.LinkedHashMap; import java.util.Map; public class LruCache<K, V> { private final LinkedHashMap<K, V> map; private int size; private int maxSize; private int putCount; private int createCount; private int evictionCount; private int hitCount; private int missCount; 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); } 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++; } 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; } } 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; } private 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); 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; } protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {} 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; } 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 } 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; } /** * 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); } }
从源代码中,我们可以清晰的看出LruCache的缓存机制。
-------------------------------------------------------------------
更多交流,Android开发联盟QQ群:272209595
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。