Android-Universal-Image-Loader学习笔记(3)--内存缓存

前面的两篇博客写了文件缓存,现在说说Android-Universal-Image-Loader的内存缓存,该内存缓存涉及到的类如图所示

这些类的继承关系如下图所示:

如同文件缓存一样,内存缓存涉及的接口也有两个:MemoryCacheAware 和MemoryCache,其中MemoryCache只是简单的继承了MemoryCacheAware并没有声明其他的方法。MemoryCacheAware接口的方法如下:

@Deprecated
public 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放入缓存
	@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<Bitmap, Integer> valueSizes = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());

  具体的removeNext()实现:

 

      /**
	 * 循环遍历valueSizes,并获取最大的那个bitmap,并且从map中删除之 
         返回的Bimmap对象交给父类的hardCache删除
	 */
	@Override
	protected 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;">@Override
	public 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()方法实现:

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

	@Override
	protected Reference<Bitmap> createReference(Bitmap value) {
		return new WeakReference<Bitmap>(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<String, Bitmap> lruCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(INITIAL_CAPACITY, LOAD_FACTOR, true));
具体的removeNext()方法实现:

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

	@Override
	protected Reference<Bitmap> createReference(Bitmap value) {
		return new WeakReference<Bitmap>(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<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());
当调用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<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;
	}

	@Override
	protected Reference<Bitmap> createReference(Bitmap value) {
		return new WeakReference<Bitmap>(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<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
	}

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




Android-Universal-Image-Loader学习笔记(3)--内存缓存,,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。