android:LruCache缓存小结

原理:

LruCache以键值对的形式,初始化时,需要设置缓存的大小K,超过这个大小的数据将会被清除。注意:清除的数据,是那些被先加入的数据。LruCache内部的数据结构是LinkedHashMap存储的。这样,LruCache就达到了缓存最近put的K个数据。

 

使用:
[code]

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. int cacheSize = 4 * 1024 * 1024; // 4MiB  
  2.    LruCache bitmapCache = new LruCache(cacheSize) {  
  3.        protected int sizeOf(String key, Bitmap value) {  
  4.            return value.getByteCount();  
  5.          
  6.    }}  


注意,缓存不同的数据,需要重写sizeOf方法。比如,上面缓存的是图片。本质上,这些数据都是存储在内存中的,因此,cacheSize不易过大。

 

 

LruCache源代码:

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. import java.util.LinkedHashMap;  
  2. import java.util.Map;  
  3.    
  4. public class LruCache<K, V> {  
  5.     private final LinkedHashMap<K, V> map;  
  6.    
  7.     private int size;  
  8.     private int maxSize;  
  9.    
  10.     private int putCount;  
  11.     private int createCount;  
  12.     private int evictionCount;  
  13.     private int hitCount;  
  14.     private int missCount;  
  15.    
  16.     public LruCache(int maxSize) {  
  17.         if (maxSize <= 0) {  
  18.             throw new IllegalArgumentException("maxSize <= 0");  
  19.         }  
  20.         this.maxSize = maxSize;  
  21.         this.map = new LinkedHashMap<K, V>(0, 0.75f, true);  
  22.     }  
  23.    
  24.     public final V get(K key) {  
  25.         if (key == null) {  
  26.             throw new NullPointerException("key == null");  
  27.         }  
  28.    
  29.         V mapValue;  
  30.         synchronized (this) {  
  31.             mapValue = map.get(key);  
  32.             if (mapValue != null) {  
  33.                 hitCount++;  
  34.                 return mapValue;  
  35.             }  
  36.             missCount++;  
  37.         }  
  38.    
  39.         V createdValue = create(key);  
  40.         if (createdValue == null) {  
  41.             return null;  
  42.         }  
  43.    
  44.         synchronized (this) {  
  45.             createCount++;  
  46.             mapValue = map.put(key, createdValue);  
  47.    
  48.             if (mapValue != null) {  
  49.                 // There was a conflict so undo that last put  
  50.                 map.put(key, mapValue);  
  51.             } else {  
  52.                 size += safeSizeOf(key, createdValue);  
  53.             }  
  54.         }  
  55.    
  56.         if (mapValue != null) {  
  57.             entryRemoved(false, key, createdValue, mapValue);  
  58.             return mapValue;  
  59.         } else {  
  60.             trimToSize(maxSize);  
  61.             return createdValue;  
  62.         }  
  63.     }  
  64.    
  65.     public final V put(K key, V value) {  
  66.         if (key == null || value == null) {  
  67.             throw new NullPointerException("key == null || value == null");  
  68.         }  
  69.    
  70.         V previous;  
  71.         synchronized (this) {  
  72.             putCount++;  
  73.             size += safeSizeOf(key, value);  
  74.             previous = map.put(key, value);  
  75.             if (previous != null) {  
  76.                 size -= safeSizeOf(key, previous);  
  77.             }  
  78.         }  
  79.    
  80.         if (previous != null) {  
  81.             entryRemoved(false, key, previous, value);  
  82.         }  
  83.    
  84.         trimToSize(maxSize);  
  85.         return previous;  
  86.     }  
  87.    
  88.     private void trimToSize(int maxSize) {  
  89.         while (true) {  
  90.             K key;  
  91.             V value;  
  92.             synchronized (this) {  
  93.                 if (size < 0 || (map.isEmpty() && size != 0)) {  
  94.                     throw new IllegalStateException(getClass().getName()  
  95.                             + ".sizeOf() is reporting inconsistent results!");  
  96.                 }  
  97.    
  98.                 if (size <= maxSize || map.isEmpty()) {  
  99.                     break;  
  100.                 }  
  101.    
  102.                 Map.Entry<K, V> toEvict = map.entrySet().iterator().next();  
  103.                 key = toEvict.getKey();  
  104.                 value = toEvict.getValue();  
  105.                 map.remove(key);  
  106.                 size -= safeSizeOf(key, value);  
  107.                 evictionCount++;  
  108.             }  
  109.    
  110.             entryRemoved(true, key, value, null);  
  111.         }  
  112.     }  
  113.    
  114.     public final V remove(K key) {  
  115.         if (key == null) {  
  116.             throw new NullPointerException("key == null");  
  117.         }  
  118.    
  119.         V previous;  
  120.         synchronized (this) {  
  121.             previous = map.remove(key);  
  122.             if (previous != null) {  
  123.                 size -= safeSizeOf(key, previous);  
  124.             }  
  125.         }  
  126.    
  127.         if (previous != null) {  
  128.             entryRemoved(false, key, previous, null);  
  129.         }  
  130.    
  131.         return previous;  
  132.     }  
  133.    
  134.     protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}  
  135.    
  136.     protected V create(K key) {  
  137.         return null;  
  138.     }  
  139.    
  140.     private int safeSizeOf(K key, V value) {  
  141.         int result = sizeOf(key, value);  
  142.         if (result < 0) {  
  143.             throw new IllegalStateException("Negative size: " + key + "=" + value);  
  144.         }  
  145.         return result;  
  146.     }  
  147.    
  148.     protected int sizeOf(K key, V value) {  
  149.         return 1;  
  150.     }  
  151.    
  152.     /** 
  153.      * Clear the cache, calling {@link #entryRemoved} on each removed entry. 
  154.      */  
  155.     public final void evictAll() {  
  156.         trimToSize(-1); // -1 will evict 0-sized elements  
  157.     }  
  158.    
  159.     public synchronized final int size() {  
  160.         return size;  
  161.     }  
  162.    
  163.     public synchronized final int maxSize() {  
  164.         return maxSize;  
  165.     }  
  166.    
  167.     public synchronized final int hitCount() {  
  168.         return hitCount;  
  169.     }  
  170.    
  171.     public synchronized final int missCount() {  
  172.         return missCount;  
  173.     }  
  174.    
  175.     public synchronized final int createCount() {  
  176.         return createCount;  
  177.     }  
  178.    
  179.     /** 
  180.      * Returns the number of times {@link #put} was called. 
  181.      */  
  182.     public synchronized final int putCount() {  
  183.         return putCount;  
  184.     }  
  185.    
  186.     /** 
  187.      * Returns the number of values that have been evicted. 
  188.      */  
  189.     public synchronized final int evictionCount() {  
  190.         return evictionCount;  
  191.     }  
  192.    
  193.     /** 
  194.      * Returns a copy of the current contents of the cache, ordered from least 
  195.      * recently accessed to most recently accessed. 
  196.      */  
  197.     public synchronized final Map<K, V> snapshot() {  
  198.         return new LinkedHashMap<K, V>(map);  
  199.     }  
  200.    
  201.     @Override public synchronized final String toString() {  
  202.         int accesses = hitCount + missCount;  
  203.         int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;  
  204.         return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",  
  205.                 maxSize, hitCount, missCount, hitPercent);  
  206.     }  
  207. }  



 

从源代码中,我们可以清晰的看出LruCache的缓存机制。

还有一个开源的缓存DiskLruCache,源代码:https://github.com/JakeWharton/DiskLruCache

posted @ 2016-11-29 15:31  天涯海角路  阅读(72)  评论(0)    收藏  举报