UniversalImageLoader源码解析之 MomoryCache
来源:互联网 发布:海关出口数据免费查询 编辑:程序博客网 时间:2024/06/05 11:35
转载请注明出处:http://blog.csdn.net/crazy1235/article/details/70472982
- MemoryCache
- LruMemoryCache
- LimitedAgeMemoryCache
- FuzzyKeyMemoryCache
- BaseMemoryCache
- WeakMemoryCache
- LimitedMemoryCache
- LRULimitedMemoryCache
- LargestLimitedMemoryCache
- FIFOLimitedMemoryCache
- UsingFreqLimitedMemoryCache
- MemoryCache
MemoryCache
从上图可以看出 MemoryCache 是内存缓存的接口,里面定义了内存缓存的先关操作,比如:读取一个缓存,放入一个缓存,移除一个缓存,清空缓存!
ImageLoaderConfiguration builder的时候
private void initEmptyFieldsWithDefaultValues() { // 省略代吗 if (memoryCache == null) { memoryCache = DefaultConfigurationFactory.createMemoryCache(context, memoryCacheSize); } if (denyCacheImageMultipleSizesInMemory) { memoryCache = new FuzzyKeyMemoryCache(memoryCache, MemoryCacheUtils.createFuzzyKeyComparator()); } // 省略代吗 }
可以看到,当memoryCache为空时,会通过工厂方法分配一个缓存策略。当不允许缓存同一张图片多种尺寸时,创建了一个 FuzzyKeyMemoryCache 缓存策略!
在 DefaultConfigurationFactory 中,UIL给我们初始化了默认的内存缓存策略!
public static MemoryCache createMemoryCache(Context context, int memoryCacheSize) { if (memoryCacheSize == 0) { ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); int memoryClass = am.getMemoryClass(); if (hasHoneycomb() && isLargeHeap(context)) { memoryClass = getLargeMemoryClass(am); } memoryCacheSize = 1024 * 1024 * memoryClass / 8; } return new LruMemoryCache(memoryCacheSize); }
默认策略是 LruMemoryCache 。缓存大小为app可获得最大内存的1/8
LruMemoryCache
当超过我们设置的缓存容量时,优先删除最近最久为使用的缓存!
内部维护一个 LinkedHashMap
private final LinkedHashMap<String, Bitmap> map;private int size; // 当前缓存的大小private final int maxSize; // 最大允许缓存总量的大小
@Override public final Bitmap get(String key) { if (key == null) { throw new NullPointerException("key == null"); } synchronized (this) { return map.get(key); } }
get() 不用多说,直接从map里面根据key取出bitmap即可!
@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; } }
remove 也是,直接从map移除对应key的那条记录!
最主要的是put() 函数!它涉及到,当容量超过maxSize时要移除部分缓存的操作!
@Override public final boolean put(String key, Bitmap value) { if (key == null || value == null) { throw new NullPointerException("key == null || value == null"); } synchronized (this) { size += sizeOf(key, value); // 1. Bitmap previous = map.put(key, value); if (previous != null) { size -= sizeOf(key, previous); } } // 2. trimToSize(maxSize); return true; }
注释1处,当previous不为空时,表示之前已经有该key对应的缓存,现在需要放入新的bitmap对象。
所以就需要把之前的给移除掉! 新的缓存放在map的最后一位!
所以此时map最前面的就是最近最久为使用的!!!
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); } } }
trimToSize() 有个while循环,只要size >maxSize 就不断的从LinkedHashMap 的头部取出一条删除!
@Override public void clear() { trimToSize(-1); // -1 will evict 0-sized elements }
清空缓存的操作直接调用 trimToSize 传入-1,这样直到map为空break循环!
LimitedAgeMemoryCache
不限制缓存大小,限制缓存存货周期!当超过我们设置的时间长度就会被删除!
private final long maxAge;private final Map<String, Long> loadingDates = Collections.synchronizedMap(new HashMap<String, Long>());
@Override public boolean put(String key, Bitmap value) { boolean putSuccesfully = cache.put(key, value); if (putSuccesfully) { loadingDates.put(key, System.currentTimeMillis()); //当前时间! } return putSuccesfully; }
由于没有限制大小,所以put操作没有什么特别的限制!
@Override public Bitmap remove(String key) { loadingDates.remove(key); return cache.remove(key); }
@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); }
get() 操作回去判断缓存的存货周期,如果大于maxAge,则会从Map中删除!!!
@Override public Bitmap remove(String key) { loadingDates.remove(key); return cache.remove(key); }
@Override public void clear() { cache.clear(); loadingDates.clear(); }
FuzzyKeyMemoryCache
denyCacheImageMultipleSizesInMemory = true;
如果不允许缓存同一张图片的多个尺寸,则使用 FuzzyKeyMemoryCache 做策略,同一个图片新的尺寸会覆盖缓存中该图片老的尺寸。
@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); }
BaseMemoryCache
它是一个实现了 MemoryCache 主要函数的抽象类。以引用的方式保存bitmap,便于虚拟机在内存不足时回收缓存对象。
private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>());
Reference 可以是 WeakReference or SoftReference !
子类需要实现它的抽象方法:
protected abstract Reference<Bitmap> createReference(Bitmap value);
WeakMemoryCache
它以 WeakReference < Bitmap > 做为 value , 实现了BaseMemoryCache。
实现了createReference(Bitmap value)函数,直接创建一个 WeakReference < Bitmap > (value)做为缓存 value。
@Override protected Reference<Bitmap> createReference(Bitmap value) { return new WeakReference<Bitmap>(value); }}
LimitedMemoryCache
也是继承于 BaseMemoryCache!
限制存储容量的内存缓存策略!
最大容量为16M
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;
所以会在 put 的时候判断是否超出上限,然后根据具体的子类策略删除某些缓存!
protected abstract int getSize(Bitmap value); // 每个元素大小protected abstract Bitmap removeNext(); // 决定删除的对象
LRULimitedMemoryCache
继承自 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));
使用 LinkedHashMap 做缓存!
LinkedHashMap 第三个参数表示是否需要根据访问顺序(accessOrder)排序。
true 表示根据accessOrder排序,最近访问的跟最新加入的一样放到最后面;
false 表示按照之前的顺序插入。
这里为 true ,所以当缓存满时,会删除map首位的元素!
@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; }
LargestLimitedMemoryCache
优先删除最大的缓存!!
public class LargestLimitedMemoryCache extends LimitedMemoryCache
private final Map<Bitmap, Integer> valueSizes = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());
@Override protected Reference<Bitmap> createReference(Bitmap value) { return new WeakReference<Bitmap>(value); }
也是使用 WeakReference< Bitmap >
重点看 removeNext()
@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; }
for循环找到最大的元素,然后从map中删除!
FIFOLimitedMemoryCache
限制缓存总容量的大小,并且会在缓存满时优先删除最先加入的缓存!
private final List<Bitmap> queue = Collections.synchronizedList(new LinkedList<Bitmap>());
@Override protected Bitmap removeNext() { return queue.remove(0); }
removeNext 直接删除列表首元素!
UsingFreqLimitedMemoryCache
限制总缓存容量大小,并且会在缓存满时优先删除使用次数最少的缓存!
private final Map<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());
每次get() 都将当前缓存使用次数 +1
@Override public Bitmap get(String key) { Bitmap value = super.get(key); if (value != null) { Integer usageCount = usingCounts.get(value); if (usageCount != null) { usingCounts.put(value, usageCount + 1); } } return value; }
@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; }
removeNext 中 循环找出使用次数最多的元素,并删除!
OK!以上就是UIL库中提供的基础中内存缓存策略!
- UniversalImageLoader源码解析之 MomoryCache
- UniversalImageLoader源码解析之 DiskCache
- UniversalImageLoader源码解析之总体流程
- UniversalImageLoader源码解析之任务处理
- UniversalImageLoader 源码解析 -1.enam(枚举)使用
- UniversalImageLoader源码分析之二、示例分析
- UniversalImageLoader 源码笔记(1)
- universalimageloader 最新版解析
- UniversalImageLoader
- UniversalImageLoader
- universalimageloader
- UniversalImageLoader源码分析之一、开发入门
- UniversalImageLoader源码解读04-内存缓存
- UniversalImageLoader源码解读05-磁盘缓存
- UniversalImageLoader源码解读06-任务调度
- supermarket 之源码解析
- EventBus之源码解析
- EventBus之源码解析
- z-index属性失效原因及解决办法
- Oracle笔记3
- 把排序数组转换为高度最小的二叉搜索树
- 通过脚本学shell之变量操作
- 1022. D进制的A+B
- UniversalImageLoader源码解析之 MomoryCache
- Ubuntu16.04 下安装 MySQL 及配置
- Python所有模块
- Oracle笔记4
- 张正友相机标定Opencv实现以及标定流程&&标定结果评价&&图像矫正流程解析(附标定程序和棋盘图)
- 20153735--2
- selenium2java写一个遍历一些元素的个别属性的方法
- TabLayout的用法进行总结和归纳
- 二叉树操作