Simple read of the LruCache source code in the android. support. v4 package, androidlrucache
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, it is moved to the head of a queue. when a value is * added to a full cache, the value at the end of that queue is evicted and may * become eligible for garbage collection. * Cache stores a strong reference to limit the number of content. When an Item is accessed, the Item will be moved The header of the queue. * When a new item is added when the cache is full, items at the end of the queue will be recycled. * <P> If your cached values hold resources that need to be explicitly released, * override {@ link # entryRemoved }. * If a value of your cache needs to be explicitly released, rewrite entryRemoved () * <p> If a cache miss shocould be computed on demand for the corresponding keys, * override {@ link # create }. this simplifies the calling code, allowing it to * assume a value will always be returned, even when there's a cache miss. * If the item corresponding to the key is lost Write create (). This simplifies the call code, and will always return even if it is lost. * <P> By default, the cache size is measured in the number of entries. override * {@ link # sizeOf} to size the cache in different units. for example, this cache * is limited to 4MiB of bitmaps: the default cache size is the number of measured items. Override sizeof to calculate the * size of different items. * <Pre >{@ code * 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 (); *} * }}</pre> ** <p> This class is thread-safe. perform multiple cache operations atomically by * synchronizing on the cache: <pre >{@ code * synchronized (cache) {* if (cache. Get (key) = null) {* cache. put (key, value); *} * }}</pre> ** <p> This class does not allow null to be used as a key or value. A return * value of null from {@ link # get}, {@ link # put} or {@ link # remove} is * unambiguous: the key was not in the cache. * key or value is not allowed to be null * When get (), put (), remove () returns null, the corresponding key item is not in the cache */public class LruCache <K, V> {private final LinkedHashMap <K, V> map;/** Si Ze of this cache in units. not necessarily the number of elements. */private int size; // the size of the private int maxSize that has been stored; // the specified maximum storage space private int putCount; // The number of put Times private int createCount; // create Times private int evictionCount; // times of recovery private int hitCount; // times of hit private int missCount; // number of lost times/*** @ param maxSize for caches that do not override {@ link # sizeOf}, this is * the maximum number of ent Ries 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 );} /*** 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. return the corresponding item through the key, or create and return the corresponding item. The corresponding item is moved to the queue header. * If the item value is not cached or cannot be created, null is returned. */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 hit;} missCount ++; // lost}/** 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. * if it is lost, try to create an item */V createdValue = create (key); if (createdValue = null) {retu Rn null;} synchronized (this) {createCount ++; // create ++ mapValue = map. put (key, createdValue); if (mapValue! = Null) {// There was a conflict so undo that last put // if There is oldValue in front, cancel 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 | v Alue = null ");} V previous; synchronized (this) {putCount ++; size + = safeSizeOf (key, value); previous = map. put (key, value); if (previous! = Null) {// The returned previous value size-= safeSizeOf (key, previous) ;}} if (previous! = Null) {entryRemoved (false, key, previous, value) ;}trimtosize (maxSize); return previous ;} /*** @ param maxSize the maximum size of the cache before returning. may be-1 * to evict even 0-sized elements. * clear cache space */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) {break;} Map. entry <K, V> toEvict = map. eldest (); if (toEvict = null) {break;} key = toEvict. getKey (); value = toEvict. getValue (); map. remove (key); size-= safeSizeOf (key, value); evictionCount ++;} entryRemoved (true, key, value, null );}} /*** Removes the entry for {@ code key} if it exists. * Delete the cache entry corresponding to the key and return the corresponding value * @ return the previous value mapped by {@ code k Ey }. */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. * called when items are recycled or deleted. This method is used when the value is recycled and the bucket is removed and called * or put when the item value is replaced. By default, nothing is done. * <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 }. * true --- indicates that the space is deleted; false --- put or remove causes * @ param newValue the new value for {@ code key}, if it exists. if non-null, * this removal was cause D 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. * when an Item is lost, it is called, and The corresponding value or null calculated is returned * <p> The me Thod 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 CILS {@ 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 u Nits. the default implementation returns 1 so that size * is the number of entries and max size is the maximum number of entries. * returns the size of a user-defined item. By default, 1 indicates the number of items, the maximum size is the maximum item value * <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. * clear cacke */public final voi D 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 {@ lin K # 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. * return the number of recycled items */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. returns the copy of the current cache, from the least recent access to the maximum access */public synchronized final Map <K, V> snapshot () {return new LinkedHashMap <K, v> (map) ;}@ Override pu Blic 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 );}}