Universal-image-loader's Memory cache policy
1. Use only strong reference caching
- Lrumemorycache (This class is the default memory cache class for the open source framework, which caches the strong references of bitmap)
2. A cache with strong references and weak references
- U Singfreqlimitedmemorycache (if the total number of cached pictures exceeds the limit, first delete the bitmap with the least frequency)
- < Span style= "Font-family:microsoft Yahei; Background-color:inherit ">lrulimitedmemorycache (this is also used by the LRU algorithm, and Lrumemorycache is different, he caches a weak reference to bitmap)
Li style= "background-color:inherit" > Fifolimitedmemorycache (FIFO caching policy, first delete the bitmap that was first added to the cache when exceeding the set value)
- < Span style= "Font-family:microsoft Yahei; Background-color:inherit ">largestlimitedmemorycache (delete the largest bitmap object first when exceeding the cache limit)
- Limitedagememorycache (Delete the bitmap when it has been added to the cache for more than the value we set)
3. Use only weak reference caching
- Weakmemorycache (there is no limit to the total size of this type of cache bitmap, the only thing that is not stable, cached images are easily recycled)
Lrumemorycache Source:
Package Com.nostra13.universalimageloader.cache.memory.impl; Import Android.graphics.bitmap;import Com.nostra13.universalimageloader.cache.memory.memorycache;import Java.util.collection;import java.util.hashset;import java.util.linkedhashmap;import java.util.map;/* Open source Framework default memory cache class, A strong reference to the cache bitmap, whose implementation is similar to the Android.support.v4.util.LruCache class, is implemented by Linkedhashmap delegation, where the k,v of lruchace is cured separately for string, and bitmap and simplifies the implementation of some of these functions *//* Note that Linkedhashmap is non-linear safe, so pass synchronized[' s?? KR?NA?ZD] To manually implement thread safety */public class Lrumemorycache implements MemoryCache {private final linkedhashmap<string, Bitmap > map; Defines the maximum cache size private final int maxSize; /** the actual size of the cache (in bytes) */private int size; Bitmap total maximum size in/**maxsize:cache (note that this is not the number, but the memory size value of the cache, as described in the following sizeof () function) */public Lrumemorycache (int maxSize) { if (maxSize <= 0) {throw new IllegalArgumentException ("maxSize <= 0"); } this.maxsize = MaxSize; This.map = new Linkedhashmap<strinG, bitmap> (0, 0.75f, true); /** linkedhashmap (int initialcapacity, float loadfactor, boolean accessorder) parameter Accessorder set to True is important, the true table will be sorted in order of access, most recently accessed in the first place, and the oldest accessed at the back see: http://www.cnblogs.com/lzrabbit/p/3734850.html**/}/** * Get function: note Unlike HashMap and Hashtable, HashMap is a null value that supports key or value * Returns the bitmap object in the cache while moving the bitmap to the head of the queue (Linkedhashmap is automatically implemented, Because the Accessorder is already set to TRUE); * If the cache does not exist, return null/@Override (This is interface memorycacheaware<k, v> (this class has been discarded, Substituting a function in its subclass interface MemoryCache extends Memorycacheaware<string, bitmap>) public final Bitmap get (String key) { if (key = = null) {thrownew nullpointerexception ("key = = null"); }/* Plus synchronized for thread safety */synchronized (this) {return map.get (key); }}/** put <String,Bitmap> key-value pair and move the record to the head of the queue */@Override public Final Boolean put (String key, Bitmap Valu e) {/* Remove the null value in the actual application */if (key = = nulL | | Value = = null) {throw new NullPointerException ("key = = NULL | | Value = = null "); } synchronized (this) {size = SizeOf (key, value); /*put is a function of HashMap, Linkedhashmap is not rewritten; Returns the previous value value of the key key, and returns null*/Bitmap previous = Map.put If it does not exist (key, value); Note here that when key already exists, update value value, to subtract previous's bitmap memory size if (previous! = null) {size = SizeOf (key, pre vious); }}/* After adding a new image, be careful to determine whether to exceed the maximum cache memory, to respond to adjustment */TrimToSize (maxSize); return true; }/** * Deletes the oldest key-value pair until the remaining key-value pair memory value is less than or equal to the standard maximum value */private void trimtosize (int maxSize) {while (true) { String key; Bitmap value; Synchronized (this) {if (Size < 0 | | (Map.isempty () && size! = 0)) {thrownew illegalstateexception (GetClass (). GetName () + ". SizeOf () is reporting inconsistent results!" ); } /** does not exceed the alert value, there is no need to process */if (size <= maxSize | | map.isempty ()) {break; The/************* storage bitmap value is more efficient than the usual way of ****************//** traversing the map, using an iterator to traverse, and gradually removing the end value Until memory requirements are met *//*** (interface) Map.entry is a key/value mapping contained in a map.**/map.entry <string, bitmap> toevict = Map.entryset (). iterator (). Next (); /* To note that the list is empty after multiple deletions */if (toevict = = null) {break; } key = Toevict.getkey (); Value = Toevict.getvalue (); Map.Remove (key); Size-= sizeOf (key, value); }}}/** remove function, delete the key value corresponding to the specific key pair **/@Override public final Bitmap remove (String key) {if (key = = null) {throw new NullPointerException ("key = = null"); } synchronized (this) {/*** hashmap.remove () function return value: The value of the REMoved mapping or null if no mapping for the specified key is found.*/Bitmap previous = Map.remov E (key); if (previous! = null) {size = SizeOf (key, previous); } return previous; }} @Override public collection<string> keys () {synchronized (this) {return new Hashse T<string> (Map.keyset ()); }} @Override public void Clear () {trimtosize ( -1);//MaxSize is assigned to 1 to achieve a clear effect, but why not use map's clear () directly; }/** * Returns the size of the bitmap for the key corresponding to how much bytes * Note that a key value pair's size should remain unchanged in the cache */private int sizeOf (String key, Bitma P value) {return value.getrowbytes () * Value.getheight (); } @Override public synchronized final String toString () {return String.Format ("lrucache[maxsize=%d]", maxsi Ze); }}
lrumemorycache is actually a simple implementation of the Android LRUCache, the following is attached LRUCache source code:
<pre class= "java" name= "code" >package android.support.v4.util; Import Java.util.linkedhashmap;import Java.util.map;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; Number of records added private int createcount; private int evictioncount;//The number of records deleted private int hitCount; The number of records hit by the query private int misscount; Number of records for query misses/** * @param maxSize for caches that does not override {@link #sizeOf}, this is * the maximum n Umber of entries in the cache. For any other caches, * this is the maximum sum of the sizes of the entries in this cache. */Public LruCache (intmaxsize) {if (maxSize <= 0) {throw new IllegalArgumentException ("MaxSize & lt;= 0 "); } this.maxsize = MaxSize; This.map = new linkedhashmap<k, v> (0, 0.75f, true); }/** * Returns the value for {@code key} If it is exists in the cache or can being * created by {@code #create}. If A value was returned, it's moved to the * head of the queue. This returns null if a value is not cached and cannot * be created. */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 is a long time, and the map * May is different when create () returns. If a conflicting value is * added to the map while create () is working, we leave that value in * the map and release the created value. *//** Here is a case where get gets the Mapvalue value null, used to eat a new key value **/V Createdvalue = Create (key); if (Createdvalue = = null) {return null; } synchronized (this) {createcount++; Mapvalue = Map.put (key, Createdvalue); if (mapvalue! = null) {//There is a conflict so undo the last put Map.put (key, Mapvalue) ; } else {size + safesizeof (key, Createdvalue); }} if (Mapvalue! = null) {entryremoved (False, Key, Createdvalue, Mapvalue); return mapvalue; } else {trimtosize (maxSize); Returncreatedvalue; }}/** * 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 Nullpointerexce Ption ("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; }/** * Remove the eldest entries until the total of remaining entries are 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. */public void TrimToSize (intmaxsize) {while (true) {K key; V value; Synchronized (this) {if (Size < 0 | | (Map.isempty () && size! = 0)) {throw new IllegalStateException (GetClass (). GetName () + ". SizeOf () is Repor Ting 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); }}/** * Removes the entry for {@code key} if it exists. * * @return The previous value mapped by {@code key}. */Public final V remove (K key) {if (key = = null) {thrownew 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 has been evicted or removed. This method was * invoked when a value was evicted to make space, removed by a call to * {@link #remove}, or replace D by a call to {@link #put}. The default * implementation does nothing. * * <p>the method is called without synchronization:other threads may * access the cache and this method is executing. * * @param evicted True if the entry is being removed to make space, false * if the removal were caused by a {@ Link #put} or {@link #remove}. * @param newvalue The new value for {@code key}, if it exists. If Non-null, * This removal is caused by a {@link #put}. Otherwise it is caused by * a eviction or a {@link #remove}. */protected void entryremoved (Boolean evicted, K key, v OldValue, v newvalue) {}/** * called after a cache mi SS 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 and this method is executing. * * <p>if a value for {@code key} exists in the ' cache when ' this method * returns, the created value would 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} and 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 units. The default implementation returns 1 so, size * is the number of entries and max size is the maximum number of ENT Ries. * * <p>an entry ' s size must not change while it's in the cache. */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 would evict 0-sized elements}/** * for cache s that does 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 intsize () {return size; }/** * For caches does not override {@link #sizeOf}, this returns the maximum * number of entries in the C Ache. For all and 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. */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 has 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? (hitcount/accesses): 0; Return String.Format ("lrucache[maxsize=%d,hits=%d,misses=%d,hitrate=%d%%"), MaxSize, HitCount, Misscount, H Itpercent); }}
Android Open source Framework Universal-image-loader Learn two--lrumemorycache source reading