深入解析开源项目之Universal-Image-Loader缓存篇
Posted 672530440
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入解析开源项目之Universal-Image-Loader缓存篇相关的知识,希望对你有一定的参考价值。
珍惜作者劳动成果,如需转载,请注明出处。
http://blog.csdn.net/zhengzechuan91/article/details/50292871
Universal-Image-Loader 是一个优秀的图片加载开源项目,Github地址在 (Github地址) ,很多童鞋都在自己的项目中用到了。优秀的项目从来都是把简单留给开发者,把复杂封装在框架内部。ImageLoader作为Github上Star数过万的项目,备受开发者青睐,所以我们有必要搞清楚它的内部实现。
在上一篇博客中我们分析了ImageLoader框架的整体实现原理,还没有看过的直接到 深入解析开源项目之ImageLoader(一)框架篇 。
ImageLoader之内存缓存篇
项目截图:
由上图我们可以看出:
MemoryCache
package com.nostra13.universalimageloader.cache.memory; import android.graphics.Bitmap; import java.util.Collection; public interface MemoryCache { boolean put(String key, Bitmap value); Bitmap get(String key); Bitmap remove(String key); Collection<String> keys(); void clear(); }
BaseMemoryCache,LimitedAgeMemoryCache,LruMemoryCache,FuzzyKeyMemoryCache
public abstract class BaseMemoryCache implements MemoryCache { private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>()); @Override public Bitmap get(String key) { Bitmap result = null; Reference<Bitmap> reference = softMap.get(key); if (reference != null) { result = reference.get(); } return result; } @Override public boolean put(String key, Bitmap value) { softMap.put(key, createReference(value)); return true; } @Override public Bitmap remove(String key) { Reference<Bitmap> bmpRef = softMap.remove(key); return bmpRef == null ? null : bmpRef.get(); } @Override public Collection<String> keys() { synchronized (softMap) { return new HashSet<String>(softMap.keySet()); } } @Override public void clear() { softMap.clear(); } protected abstract Reference<Bitmap> createReference(Bitmap value); }
public class LimitedAgeMemoryCache implements MemoryCache {//也是对MemoryCache的装饰 private final MemoryCache cache; private final long maxAge; private final Map<String, Long> loadingDates = Collections.synchronizedMap(new HashMap<String, Long>()); 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; }
//对MemeryCache的get(String key)做了加强处理:当我们在获取内存Cache中的Bitmap时,如果超过最大存活时间则不返回 @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 Bitmap remove(String key) { loadingDates.remove(key); return cache.remove(key); } @Override public Collection<String> keys() { return cache.keys(); } @Override public void clear() { cache.clear(); loadingDates.clear(); } }
//开源框架默认的内存缓存类,缓存的是bitmap的强引用,
public class LruMemoryCache implements MemoryCache {
private final LinkedHashMap<String, Bitmap> map;
//缓存设定的最大值,maxSize 默认的情况下是程序进程占用内存总数的八分之一,单位是Byte。
private final int maxSize;
//** 缓存中已经占有的大小
private int size;
public LruMemoryCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
//true表示排序的顺序是从最远使用到最近使用,而返回false顺序则为插入时的顺序。
this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);
}
@Override
public final Bitmap get(String key) {
if (key == null) {
throw new NullPointerException("key == null");
}
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) {
//调用sizeOf这个函数获得该bitmap对象的占用内存的大小,并且让缓存总数增加
size += sizeOf(key, value);
//这里就是把对象放入容器中的最核心的一句代码,put()方法如果容器中已经有了此元素,则返回该元素的value值,否则添加进去并返回空
Bitmap previous = map.put(key, value);
if (previous != null) {
//如果容器中已经有了此元素,则需要把增加的数量减掉
size -= sizeOf(key, previous);
}
}
//此函数计算是否超出最大限量,是则删除队尾元素
trimToSize(maxSize);
return true;
}
//删除最先加入的元素,移除最远使用的Bitmap
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;
}
//获取最先加入的元素
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);
}
}
}
@Override
public final Bitmap remove(String key) {
if (key == null) {
throw new NullPointerException("key == null");
}
//map实例化时并不是线程安全的,所以在所有的操作中都有同步锁。
synchronized (this) {
//存在则返回该Bitmap,不存在返回null
Bitmap previous = map.remove(key);
if (previous != null) {
////如果移除的Bitmap存在
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
}
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);
}
}
public class FuzzyKeyMemoryCache implements MemoryCache {//对MemoryCache的装饰 private final MemoryCache cache; private final Comparator<String> keyComparator; public FuzzyKeyMemoryCache(MemoryCache cache, Comparator<String> keyComparator) { this.cache = cache; this.keyComparator = keyComparator; }
/*对MemoryCache的put(String key, Bitmap value)方法进行加强处理:先移除key相同的Bitmap,再添加新的key对应的Bitmap*/ @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()) { if (keyComparator.compare(key, cacheKey) == 0) { keyToRemove = cacheKey; break; } } if (keyToRemove != null) { cache.remove(keyToRemove); } } return cache.put(key, value); } @Override public Bitmap get(String key) { return cache.get(key); } @Override public Bitmap remove(String key) { return cache.remove(key); } @Override public void clear() { cache.clear(); } @Override public Collection<String> keys() { return cache.keys(); } }
LimitedMemoryCache,WeakMemoryCache
//重写LimitedMemoryCache主要是来实现removeNext()方法,以指定超过内存最大限定后移除Bitmap的规则。
public abstract class LimitedMemoryCache extends BaseMemoryCache { private static final int MAX_NORMAL_CACHE_SIZE_IN_MB = 16; private static final int MAX_NORMAL_CACHE_SIZE = MAX_NORMAL_CACHE_SIZE_IN_MB * 1024 * 1024; private final int sizeLimit;//第2层最大缓存大小16M:多个线程只会读不会写 private final AtomicInteger cacheSize;//当前缓存的大小,原子操作:多个线程会对这个变量进行写 //强引用有引用变量指向时永远不会被垃圾回收。即使内存不足的时候宁愿报OOM也不被垃圾回收器回收,我们new的对象都是强引用 private final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>()); /** @param sizeLimit Maximum size for cache (in bytes) */ public LimitedMemoryCache(int sizeLimit) { this.sizeLimit = sizeLimit; cacheSize = new AtomicInteger(); if (sizeLimit > MAX_NORMAL_CACHE_SIZE) { L.w("You set too large memory cache size (more than %1$d Mb)", MAX_NORMAL_CACHE_SIZE_IN_MB); } } @Override public boolean put(String key, Bitmap value) { boolean putSuccessfully = false; // Try to add value to hard cache int valueSize = getSize(value); int sizeLimit = getSizeLimit(); int curCacheSize = cacheSize.get(); if (valueSize < sizeLimit) {//如果一个图片大于第2层最大值,则不用进行移除加入第2层了 while (curCacheSize + valueSize > sizeLimit) {//小于最大值加入第二层, Bitmap removedValue = removeNext();//超过第二层最大值时4种移除第2层3层策略,第一层不移除 if (hardCache.remove(removedValue)) { curCacheSize = cacheSize.addAndGet(-getSize(removedValue)); } } hardCache.add(value); cacheSize.addAndGet(valueSize); putSuccessfully = true; } // Add value to soft cache super.put(key, value);//加入第一层 return putSuccessfully; } @Override public Bitmap remove(String key) { Bitmap value = super.get(key);//第1层 if (value != null) {//第1层有 if (hardCache.remove(value)) {//第2层删除 cacheSize.addAndGet(-getSize(value)); } } return super.remove(key);//第1层删除,返回第1层删除的 } @Override public void clear() { hardCache.clear();//第2层删除 cacheSize.set(0); super.clear();//第1层删除 } protected int getSizeLimit() { return sizeLimit; } protected abstract int getSize(Bitmap value); protected abstract Bitmap removeNext(); }
//这个类缓存bitmap的总大小没有限制,唯一不足的地方就是不稳定,缓存的图片容易被回收掉 public class WeakMemoryCache extends BaseMemoryCache { @Override protected Reference<Bitmap> createReference(Bitmap value) { //弱引用通过weakReference类来实现,如果垃圾回收器扫描到有着WeakReference的对象,就会将其回收释放内存 return new WeakReference<Bitmap>(value); } }
FIFOLimitedMemoryCache,LargestLimitedMemoryCache,LRULimitedMemoryCache,UsingFreqLimitedMemoryCache
public class FIFOLimitedMemoryCache extends LimitedMemoryCache { private final List<Bitmap> queue = Collections.synchronizedList(new LinkedList<Bitmap>()); public FIFOLimitedMemoryCache(int sizeLimit) { super(sizeLimit);//设置第2层最大值 } @Override public boolean put(String key, Bitmap value) { if (super.put(key, value)) {//第2层加了,1,3层也要加 queue.add(value); return true; } else {//超过第2层总共最大值,第2,3层不添加,只加到第一层 return false; } } @Override public Bitmap remove(String key) { Bitmap value = super.get(key);//获取第1层软引用缓存有没有 if (value != null) {//第1层有 queue.remove(value);//第3层删除 } return super.remove(key);//第2层 } @Override public void clear() { queue.clear();//第3层删除 super.clear();//第2层 } @Override protected int getSize(Bitmap value) { return value.getRowBytes() * value.getHeight(); } @Override protected Bitmap removeNext() { return queue.remove(0);//删除第3层第1个 } @Override protected Reference<Bitmap> createReference(Bitmap value) { return new WeakReference<Bitmap>(value); } }
public class LargestLimitedMemoryCache extends LimitedMemoryCache { private final Map<Bitmap, Integer> valueSizes = Collections.synchronizedMap(new HashMap<Bitmap, Integer>()); public LargestLimitedMemoryCache(int sizeLimit) { super(sizeLimit);//设置第2层最大值 } @Override public boolean put(String key, Bitmap value) { if (super.put(key, value)) {//第2层加了,1,3层也要加。 valueSizes.put(value, getSize(value)); return true; } else {//第2层加不进去,3层不加,只加第一层 return false; } } @Override public Bitmap remove(String key) { Bitmap value = super.get(key);//第一层 if (value != null) {//第一层有 valueSizes.remove(value);//移除第三层 } return super.remove(key); } @Override public void clear() { valueSizes.clear(); super.clear(); } @Override protected int getSize(Bitmap value) { return value.getRowBytes() * value.getHeight(); } @Override protected Bitmap removeNext() {//删除最大的bitmap对象 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; } @Override protected Reference<Bitmap> createReference(Bitmap value) { return new WeakReference<Bitmap>(value); } }
public class LRULimitedMemoryCache extends LimitedMemoryCache { private static final int INITIAL_CAPACITY = 10; private static final float LOAD_FACTOR = 1.1f; private final Map<String, Bitmap> lruCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(INITIAL_CAPACITY, LOAD_FACTOR, true)); public LRULimitedMemoryCache(int maxSize) { super(maxSize); } @Override public boolean put(String key, Bitmap value) { if (super.put(key, value)) { lruCache.put(key, value); return true; } else { return false; } } @Override public Bitmap get(String key) { lruCache.get(key); // call "get" for LRU logic return super.get(key); } @Override public Bitmap remove(String key) { lruCache.remove(key); return super.remove(key); } @Override public void clear() { lruCache.clear(); super.clear(); } @Override protected int getSize(Bitmap value) { return value.getRowBytes() * value.getHeight(); } @Override protected Bitmap removeNext() { Bitmap mostLongUsedValue = null; synchronized (lruCache) { Iterator<Entry<String, Bitmap>> it = lruCache.entrySet().iterator(); if (it.hasNext()) { Entry<String, Bitmap> entry = it.next(); mostLongUsedValue = entry.getValue(); it.remove(); } } return mostLongUsedValue; } @Override protected Reference<Bitmap> createReference(Bitmap value) { return new WeakReference<Bitmap>(value); } }
public class UsingFreqLimitedMemoryCache extends LimitedMemoryCache { private final Map<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>()); public UsingFreqLimitedMemoryCache(int sizeLimit) { super(sizeLimit); } @Override public boolean put(String key, Bitmap value) { if (super.put(key, value)) { usingCounts.put(value, 0); return true; } else { return false; } } @Override public Bitmap get(String key) {//读取一次加1 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) { usingCounts.put(value, usageCount + 1); } } return value; } @Override public Bitmap remove(String key) { Bitmap value = super.get(key); if (value != null) { usingCounts.remove(value); } return super.remove(key); } @Override public void clear() { usingCounts.clear(); super.clear(); } @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); } }
以上是关于深入解析开源项目之Universal-Image-Loader缓存篇的主要内容,如果未能解决你的问题,请参考以下文章
iOS之深入解析CocoaPods的GitLab CI与组件自动化构建与发布