標籤:android style blog http java color
前面的兩篇部落格寫了檔案快取,現在說說Android-Universal-Image-Loader的記憶體緩衝,該記憶體緩衝涉及到的類
這些類的繼承關係如所示:
如同檔案快取一樣,記憶體緩衝涉及的介面也有兩個:MemoryCacheAware 和MemoryCache,其中MemoryCache只是簡單的繼承了MemoryCacheAware並沒有聲明其他的方法。MemoryCacheAware介面的方法如下:
@Deprecatedpublic interface MemoryCacheAware<K, V> {/** *根據key值把value放入緩衝 * @return 如果放入緩衝成功的話就返回true,反之返回false */boolean put(K key, V value);/**根據key從緩衝中擷取資料,沒有相關資料則返回null*/V get(K key);/** 根據key從緩衝中刪除資料*/void remove(K key);/** 返回緩衝中所有的key */Collection<K> keys();/** 清空緩衝*/void clear();}
下面詳細介紹這些緩衝的作用以及實現方式,先從BaseMemoryCache以及其子類開始
BaseMemoryCache:
該類是一個抽象類別,提供了一個map,用來緩衝Bitmap的弱引用:
private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>());
其中softMap的value欄位就是儲存了Bimmap的參考型別,由於Reference又分為強引用,弱引用,軟引用以及虛引用,所以該該類另外還提供了一個抽象方法createReference(Bitmap value)讓子類重寫,根據不同的要求來返回不同的應用類型。該抽象方法是將Bitmap轉換成一個Reference,在調用BaseMemoryCache的put方法時調用。
/**根據value建立一個弱引用對象,該類為抽象類別,供子類實現 */protected abstract Reference<Bitmap> createReference(Bitmap value); @Override public boolean put(String key, Bitmap value) { softMap.put(key, createReference(value)); return true; }
LimitedMemoryCache:
該類為抽象類別,繼承了BaseMemoryChache;對緩衝進行了兩個限制:
1) 限制每一個緩衝圖片的最大值:用sizeLimit來作為標緻,對大於sizeLimit大小的bitmap對象,調用父類的put方法儲存bitmap的弱引用。否則在儲存弱引用的同時,把Bitmap對象的強引用用類型為LinkedList變數hardCache緩衝起來,
2) 同樣用sizeLimit來限制整個緩衝的大小。對是否超出緩衝大小的限制在put方法被調用的時候會做判斷,如果緩衝大小超出限制就從LinkedList中刪除對應的bitmap對象,具體的刪除策略有該類的抽象方法remoeNext()提供,具體的在子父類中實現(比如有的是刪除最大的那個bitMap,以及根據FIFO演算法刪除等等),這是典型的模板方法模式的應用。具體的模板方法為romoveNext()和getSize()由相應的子類實現。
注意put方法的返回值,當要加入的bitMap的大小超過sizeLimit的就返回false,否則返回true(在子類中調用該put方法,返回true說明對緩衝進行了對應的刪除操作)
private final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>());<span style="color:#0000C0;">//hardCache</span><span style="color:#0000C0;">只是在此類中只是用來對緩衝是否超過</span><span style="color:#0000C0;">sizeLimit</span><span style="color:#0000C0;">做判斷。</span>//bitMap放入緩衝@Overridepublic boolean put(String key, Bitmap value) {boolean putSuccessfully = false;// Try to add value to hard cache//getSize方法為抽象方法,由子類實現int valueSize = getSize(value);int sizeLimit = this.sizeLimit;int curCacheSize = cacheSize.get();//當bitmap的大小小於sizeLimit的大小時if (valueSize < sizeLimit) {//對緩衝進行刪除操作,使之不超過siezeLimit的限制,。我們while (curCacheSize + valueSize > sizeLimit) {Bitmap removedValue = removeNext();//removeNext()為抽象方法,由不同的子類提供不同的刪除策略if (hardCache.remove(removedValue)) {curCacheSize = cacheSize.addAndGet(-getSize(removedValue));}}//放入緩衝hardCache.add(value);//設定緩衝大小cacheSize.addAndGet(valueSize);putSuccessfully = true;} //擷取bitMap的大小 protected abstract int getSize(Bitmap value); //模板方法,由相應的子類來實現具體的刪除策略 protected abstract Bitmap removeNext();
LargesetLimitedMemoryCache:
該類為LimitedMemoryCache的子類,該類的目的是當超出緩衝大小限制的時候刪除緩衝中最大的那個bitmap對象。該類實現了父類的兩個抽象方法:getSize()和removeNext()來擷取某個bitmap的大小和刪除最大的那個bitMap對象。
實現的原理: 該類添加了一個map變數,該map的key用來儲存bitMap對象,而對應的value則儲存bitmap的大小。
private final Map<Bitmap, Integer> valueSizes = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());
具體的removeNext()實現:
/** * 迴圈遍曆valueSizes,並擷取最大的那個bitmap,並且從map中刪除之 返回的Bimmap對象交給父類的hardCache刪除 */@Overrideprotected Bitmap removeNext() {Integer maxSize = null;Bitmap largestValue = null;Set<Entry<Bitmap, Integer>> entries = valueSizes.entrySet();synchronized (valueSizes) {for (Entry<Bitmap, Integer> entry : entries) {if (largestValue == null) {largestValue = entry.getKey();maxSize = entry.getValue();} else {Integer size = entry.getValue();if (size > maxSize) {maxSize = size;largestValue = entry.getKey();}}}}//執行刪除稻作valueSizes.remove(largestValue);return largestValue;} //擷取getSize的方法 @Override protected int getSize(Bitmap value) { return value.getRowBytes() * value.getHeight(); } @Override protected Reference<Bitmap> createReference(Bitmap value) { return new WeakReference<Bitmap>(value); }
刪除操作執行時機:調用父類put方法是執行
<span style="font-size:12px;">@Overridepublic boolean put(String key, Bitmap value) {if (super.put(key, value)) {//如果父類的方法為空白,說明緩衝的大小沒有超出限制valueSizes.put(value, getSize(value));return true;} else {//緩衝的大小超出限制return false;}}</span>
FIFOLimitedMemoryCache :
LimitedMomroyCache的子類,噹噹前緩衝的大小超出限制的時候,會根據FIFO(先進先出)演算法刪除響應的bitmap緩衝對象。該類用LinkedList來作為FIFO的實現方式,當超出緩衝大小的時候,調用removeNext()來從緩衝中刪除首先加入進來的bitmap對象。相應的方法如下:
實現原理:提供了一個LinkedList來儲存bitmap對象
private final List<Bitmap> queue = Collections.synchronizedList(new LinkedList<Bitmap>());
具體的removeNext()方法實現:
@Overrideprotected Bitmap removeNext() {return queue.remove(0);}@Overrideprotected Reference<Bitmap> createReference(Bitmap value) {return new WeakReference<Bitmap>(value);}@Overrideprotected int getSize(Bitmap value) {return value.getRowBytes() * value.getHeight();}刪除操作執行時機:調用父類put方法是執行
@Overridepublic boolean put(String key, Bitmap value) {if (super.put(key, value)) {//如果緩衝沒有超出範圍queue.add(value);//把bitmap放入隊列return true;} else {//緩衝超出範圍return false;}}
LRULimitedMemoryCache:
LimitedMemoryCache的子類,最近最久未使用緩衝,當緩衝大小超過sizeLimit限制的時候,就從緩衝中刪除最近最久未使用的bitmap緩衝對象。
實現原理:提供了一個LinkedHashMap來儲存對象,實現LRU的效果
/** Cache providing Least-Recently-Used logic */private final Map<String, Bitmap> lruCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(INITIAL_CAPACITY, LOAD_FACTOR, true));
具體的removeNext()方法實現:
@Overrideprotected Bitmap removeNext() {return queue.remove(0);}@Overrideprotected Reference<Bitmap> createReference(Bitmap value) {return new WeakReference<Bitmap>(value);}@Overrideprotected int getSize(Bitmap value) {return value.getRowBytes() * value.getHeight();}
刪除操作執行時機:調用父類put方法是執行
@Overridepublic boolean put(String key, Bitmap value) {if (super.put(key, value)) {//如果緩衝沒有超出範圍queue.add(value);//把bitmap放入隊列return true;} else {//緩衝超出範圍return false;}}
UsingFreqLimitedMemoryCache:
LimitedMemoryCache的子類,當緩衝大小超出sizelimit的時候對最久未使用的bitmap對象進行刪除(也就是說對使用次數最少的那個bitmap進行刪除操作)
實現原理:提供了一個hashMap,該map的key儲存bitmap對象,而value則儲存對應bitmap的使用次數
private final Map<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());
當調用get(string key)方法擷取bitmap的時候,該bitmap的使用次數進行+1操作
@Overridepublic Bitmap get(String key) {Bitmap value = super.get(key);// Increment usage count for value if value is contained in hardCaheif (value != null) {Integer usageCount = usingCounts.get(value);if (usageCount != null) {//使用次數+1usingCounts.put(value, usageCount + 1);}}return value;}
具體的removeNext()實現方法:
@Overrideprotected int getSize(Bitmap value) {return value.getRowBytes() * value.getHeight();}@Overrideprotected Bitmap removeNext() {Integer minUsageCount = null;Bitmap leastUsedValue = null;Set<Entry<Bitmap, Integer>> entries = usingCounts.entrySet();synchronized (usingCounts) {for (Entry<Bitmap, Integer> entry : entries) {if (leastUsedValue == null) {leastUsedValue = entry.getKey();minUsageCount = entry.getValue();} else {Integer lastValueUsage = entry.getValue();if (lastValueUsage < minUsageCount) {minUsageCount = lastValueUsage;leastUsedValue = entry.getKey();}}}}usingCounts.remove(leastUsedValue);return leastUsedValue;}@Overrideprotected Reference<Bitmap> createReference(Bitmap value) {return new WeakReference<Bitmap>(value);}
刪除操作執行時機:調用父類put方法是執行
@Overridepublic boolean put(String key, Bitmap value) {if (super.put(key, value)) {usingCounts.put(value, 0);return true;} else {return false;}}
LimitedAgeMemoryCache:
對超出時間限制的緩衝對象進行刪除,該類的實現畢竟簡單,具體代碼如下:
public class LimitedAgeMemoryCache implements MemoryCache {private final MemoryCache cache;private final long maxAge;private final Map<String, Long> loadingDates = Collections.synchronizedMap(new HashMap<String, Long>());/** * @param cache Wrapped memory cache * @param maxAge Max object age <b>(in seconds)</b>. If object age will exceed this value then it'll be removed from * cache on next treatment (and therefore be reloaded). */public LimitedAgeMemoryCache(MemoryCache cache, long maxAge) {this.cache = cache;this.maxAge = maxAge * 1000; // to milliseconds}@Overridepublic boolean put(String key, Bitmap value) {boolean putSuccesfully = cache.put(key, value);if (putSuccesfully) {loadingDates.put(key, System.currentTimeMillis());}return putSuccesfully;}@Overridepublic Bitmap get(String key) {Long loadingDate = loadingDates.get(key); //判斷是否逾時 if (loadingDate != null && System.currentTimeMillis() - loadingDate > maxAge) {cache.remove(key);loadingDates.remove(key);}return cache.get(key);}@Overridepublic void remove(String key) {cache.remove(key);loadingDates.remove(key);}@Overridepublic Collection<String> keys() {return cache.keys();}@Overridepublic void clear() {cache.clear();loadingDates.clear();}}
FuzzyKeyMemoryCache:
該緩衝的作用就是如果緩衝中的有一個key和要加入的keytemp相等,就從緩衝中刪除該key指向的bitmap對象,然後把新的key對象加入到緩衝中去。具體的邏輯如下:
@Overridepublic boolean put(String key, Bitmap value) {// Search equal key and remove this entrysynchronized (cache) {String keyToRemove = null;for (String cacheKey : cache.keys()) {//判斷緩衝中對應的key是否存在,存在就刪除if (keyComparator.compare(key, cacheKey) == 0) {keyToRemove = cacheKey;break;}}if (keyToRemove != null) {cache.remove(keyToRemove);}}return cache.put(key, value);}
LruMemoryCache:
又一個最近最久未使用緩衝,在這裡就不多說了,直接貼代碼:
@Overridepublic final boolean put(String key, Bitmap value) {synchronized (this) {size += sizeOf(key, value);Bitmap previous = map.put(key, value);if (previous != null) {size -= sizeOf(key, previous);}} //緩衝瘦身,把最近最久未使用的bitMap刪除trimToSize(maxSize);return true;}private void trimToSize(int maxSize) {while (true) {String key;Bitmap value; synchronized (this) {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);}}}