Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android-Universal-Image-Loader學習筆記(3)--內存緩存

Android-Universal-Image-Loader學習筆記(3)--內存緩存

編輯:關於Android編程

前面的兩篇博客寫了文件緩存,現在說說Android-Universal-Image-Loader的內存緩存,該內存緩存涉及到的類如圖所示

\

這些類的繼承關系如下圖所示:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+PGltZyBzcmM9"/uploadfile/Collfiles/20140711/20140711090242214.jpg" alt="\">

如同文件緩存一樣,內存緩存涉及的接口也有兩個:MemoryCacheAware 和MemoryCache,其中MemoryCache只是簡單的繼承了MemoryCacheAware並沒有聲明其他的方法。MemoryCacheAware接口的方法如下:

@Deprecated
public interface MemoryCacheAware {
	/**
	 *根據key值把value放入緩存
	 * @return 如果放入緩存成功的話就返回true,反之返回false
	 */
	boolean put(K key, V value);
	/**根據key從緩存中獲取數據,沒有相關數據則返回null*/
	V get(K key);
	/** 根據key從緩存中刪除數據*/
	void remove(K key);
	/** 返回緩存中所有的key */
	Collection keys();
	/** 清空緩存*/
	void clear();
}

下面詳細介紹這些緩存的作用以及實現方式,先從BaseMemoryCache以及其子類開始

BaseMemoryCache:

該類是一個抽象類,提供了一個map,用來緩存Bitmap的弱引用:

  private final Map> softMap = Collections.synchronizedMap(new HashMap>());

其中softMap的value字段就是保存了Bimmap的引用類型,由於Reference又分為強引用,弱引用,軟引用以及虛引用,所以該該類另外還提供了一個抽象方法createReference(Bitmap value)讓子類重寫,根據不同的要求來返回不同的應用類型。該抽象方法是將Bitmap轉換成一個Reference,在調用BaseMemoryCache的put方法時調用。

/**根據value創建一個弱引用對象,該類為抽象類,供子類實現 */
	protected abstract Reference 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 hardCache = Collections.synchronizedList(new LinkedList());//hardCache只是在此類中只是用來對緩存是否超過sizeLimit做判斷。
	//bitMap放入緩存
	@Override
	public 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 valueSizes = Collections.synchronizedMap(new HashMap());

具體的removeNext()實現:

      /**
	 * 循環遍歷valueSizes,並獲取最大的那個bitmap,並且從map中刪除之 
         返回的Bimmap對象交給父類的hardCache刪除
	 */
	@Override
	protected Bitmap removeNext() {
		Integer maxSize = null;
		Bitmap largestValue = null;
		Set> entries = valueSizes.entrySet();
		synchronized (valueSizes) {
			for (Entry 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 createReference(Bitmap value) {
        return new WeakReference(value);
    }

刪除操作執行時機:調用父類put方法是執行

@Override
	public boolean put(String key, Bitmap value) {
		if (super.put(key, value)) {//如果父類的方法為空,說明緩存的大小沒有超出限制
			valueSizes.put(value, getSize(value));
			return true;
		} else {//緩存的大小超出限制
			return false;
		}
	}

FIFOLimitedMemoryCache :

LimitedMomroyCache的子類,當當前緩存的大小超出限制的時候,會根據FIFO(先進先出)算法刪除響應的bitmap緩存對象。該類用LinkedList來作為FIFO的實現方式,當超出緩存大小的時候,調用removeNext()來從緩存中刪除首先加入進來的bitmap對象。相應的方法如下:

實現原理:提供了一個LinkedList來保存bitmap對象

private final List queue = Collections.synchronizedList(new LinkedList());

具體的removeNext()方法實現:

@Override
	protected Bitmap removeNext() {
		return queue.remove(0);
	}

	@Override
	protected Reference createReference(Bitmap value) {
		return new WeakReference(value);
	}
	
	@Override
	protected int getSize(Bitmap value) {
		return value.getRowBytes() * value.getHeight();
	}
刪除操作執行時機:調用父類put方法是執行

@Override
	public 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 lruCache = Collections.synchronizedMap(new LinkedHashMap(INITIAL_CAPACITY, LOAD_FACTOR, true));
具體的removeNext()方法實現:

@Override
	protected Bitmap removeNext() {
		return queue.remove(0);
	}

	@Override
	protected Reference createReference(Bitmap value) {
		return new WeakReference(value);
	}
	
	@Override
	protected int getSize(Bitmap value) {
		return value.getRowBytes() * value.getHeight();
	}

刪除操作執行時機:調用父類put方法是執行

@Override
	public 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 usingCounts = Collections.synchronizedMap(new HashMap());
當調用get(string key)方法獲取bitmap的時候,該bitmap的使用次數進行+1操作

@Override
	public Bitmap get(String key) {
		Bitmap value = super.get(key);
		// Increment usage count for value if value is contained in hardCahe
		if (value != null) {
			Integer usageCount = usingCounts.get(value);
			if (usageCount != null) {
				//使用次數+1
				usingCounts.put(value, usageCount + 1);
			}
		}
		return value;
	}

具體的removeNext()實現方法:

@Override
	protected int getSize(Bitmap value) {
		return value.getRowBytes() * value.getHeight();
	}

	@Override
	protected Bitmap removeNext() {
		Integer minUsageCount = null;
		Bitmap leastUsedValue = null;
		Set> entries = usingCounts.entrySet();
		synchronized (usingCounts) {
			for (Entry 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;
	}

	@Override
	protected Reference createReference(Bitmap value) {
		return new WeakReference(value);
	}

刪除操作執行時機:調用父類put方法是執行

@Override
	public 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 loadingDates = Collections.synchronizedMap(new HashMap());

	/**
	 * @param cache  Wrapped memory cache
	 * @param maxAge Max object age (in seconds). 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
	}

	@Override
	public boolean put(String key, Bitmap value) {
		boolean putSuccesfully = cache.put(key, value);
		if (putSuccesfully) {
			loadingDates.put(key, System.currentTimeMillis());
		}
		return putSuccesfully;
	}

	@Override
	public 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);
	}

	@Override
	public void remove(String key) {
		cache.remove(key);
		loadingDates.remove(key);
	}

	@Override
	public Collection keys() {
		return cache.keys();
	}

	@Override
	public void clear() {
		cache.clear();
		loadingDates.clear();
	}
}

FuzzyKeyMemoryCache:

該緩存的作用就是如果緩存中的有一個key和要加入的keytemp相等,就從緩存中刪除該key指向的bitmap對象,然後把新的key對象加入到緩存中去。具體的邏輯如下:

	@Override
	public boolean put(String key, Bitmap value) {
		// Search equal key and remove this entry
		synchronized (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:

又一個最近最久未使用緩存,在這裡就不多說了,直接貼代碼:

@Override
	public 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 toEvict = map.entrySet().iterator().next();
				if (toEvict == null) {
					break;
				}
				key = toEvict.getKey();
				value = toEvict.getValue();
				map.remove(key);
				size -= sizeOf(key, value);
			}
		}
	}




  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved