#LruMemoryCache和LruCache算法
在UniversalImageLoader中緩存在內存中的數據就使用了LruCache類,叫LruMemoryCache,存在內存中的圖片就是放在該類中了,想一想早年咱們用軟引用的方式保存,也是弱爆了...緩存
Lru(Least recently used,最近最少使用)是一個緩存淘汰算法的簡寫,若是數據長時間沒有被訪問,那麼緩存數據容量滿的的時候,將會淘汰最少使用的數據。 咱們直接看LruMemoryCache的代碼。安全
/** * A cache that holds strong references to a limited number of Bitmaps. Each time a Bitmap is accessed, it is moved to * the head of a queue. When a Bitmap is added to a full cache, the Bitmap at the end of that queue is evicted and may * become eligible for garbage collection.<br /> * <br /> * <b>NOTE:</b> This cache uses only strong references for stored Bitmaps. * * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) * @since 1.8.1 */ public class LruMemoryCache implements MemoryCache { //LinkedHashMap accessOrder設爲true之後,最近訪問的數據將會被放到前面, private final LinkedHashMap<String, Bitmap> map; private final int maxSize; /** Size of this cache in bytes */ private int size; /** @param maxSize Maximum sum of the sizes of the Bitmaps in this cache */ public LruMemoryCache(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } //maxSize universal分配的策略是分配給應用的內存的1/8 this.maxSize = maxSize; //設爲true了 this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true); } /** * Returns the Bitmap for {@code key} if it exists in the cache. If a Bitmap was returned, it is moved to the head * of the queue. This returns null if a Bitmap is not cached. */ @Override public final Bitmap get(String key) { if (key == null) { throw new NullPointerException("key == null"); } //LinkHashMap是非線程安全的,因此要本身同步,這裏get之後,LinkedHashMap就會把數據放在最前面 synchronized (this) { return map.get(key); } } /** Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue. */ @Override public final boolean put(String key, Bitmap value) { if (key == null || value == null) { throw new NullPointerException("key == null || value == null"); } synchronized (this) { //加上當前的size size += sizeOf(key, value); Bitmap previous = map.put(key, value); //若是key存在,要減去之前的size if (previous != null) { size -= sizeOf(key, previous); } } //清理緩存,若是超出最大值,則須要刪除老的數據 trimToSize(maxSize); return true; } /** * Remove the eldest entries until the total of remaining entries is 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. */ private void trimToSize(int maxSize) { while (true) { String key; Bitmap 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; } //刪除老的數據直至 size<maxSize Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next(); if (toEvict == null) { break; } key = toEvict.getKey(); value = toEvict.getValue(); map.remove(key); size -= sizeOf(key, value); } } } /** Removes the entry for {@code key} if it exists. */ @Override public final Bitmap remove(String key) { if (key == null) { throw new NullPointerException("key == null"); } synchronized (this) { Bitmap previous = map.remove(key); if (previous != null) { size -= sizeOf(key, previous); } return previous; } } @Override public Collection<String> keys() { synchronized (this) { return new HashSet<String>(map.keySet()); } } @Override public void clear() { trimToSize(-1); // -1 will evict 0-sized elements } /** * Returns the size {@code Bitmap} in bytes. * <p/> * An entry's size must not change while it is in the cache. */ private int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } @Override public synchronized final String toString() { return String.format("LruCache[maxSize=%d]", maxSize); } }
Android 4.0之後官方也引入了一個緩存類叫LruCache,能夠直接在源碼中找到該類,具體實現和上相似,只是這是一個泛型的實現,具體若是之後你們用的到,能夠去源碼中查詢。ide