UniversalImageLoader源码学习——LruMemoryCache内存缓存
来源:互联网 发布:mac系统中怎么激活ai 编辑:程序博客网 时间:2024/06/05 10:18
之前我们分析了ImageLoader的源码,它的缓存策略较为简单,在实际应用中我们更多的用的是UniversalImageLoader,下面我们阅读下它的源码,分析下它的缓存逻辑。
UniversalImageLoader采用三级缓存策略,分别是内存缓存、硬盘缓存、网络缓存。
我们今天先看内存缓存:
1、首先定义一个借口MemoryCache,供外界调用,在其中分别定义put、get、remove、clear抽象方法,用于对缓存进行操作,另定义keys()方法,用于获取关键字集合。代码如下:
public abstract interface MemoryCache{ public abstract boolean put(String paramString, Bitmap paramBitmap); public abstract Bitmap get(String paramString); public abstract Bitmap remove(String paramString); public abstract Collection<String> keys(); public abstract void clear();}
2、看抽象类BaseMemoryCache。
private final Map
public Collection<String> keys() { synchronized (this.softMap) { return new HashSet(this.softMap.keySet()); } }
3、看抽象类LimitedMemoryCache,此类主要是对cache的大小做了限定,当图片缓慢满了之后,按一定策略选出需要删除的Bitmap缓存,具体删除策略,由其子类实现。这里需注意线程同步问题,AtomicInteger是提供了原子操作的Integer的类,是线程安全的。
4、查看 FIFOLimitedMemoryCache、LRULimitedMemoryCache、LargestLimitedMemoryCache、UsingFreqLimitedMemoryCache
这四个类都是MemoryCache的实现类,继承自LimitedMemoryCache。通过名字可以看出,它们分别对应不同的缓存策略:
FIFOLimitedMemoryCache 对应的是先进先出的缓存策略,即当图片缓存满了之后,首先删除的是最先进入缓存区的图片,此时的引用为WeakReference。具体实现如下:
protected Bitmap removeNext() { return (Bitmap)this.queue.remove(0); }
LRULimitedMemoryCache 对应是最近最少使用的缓存测试,即当图片缓存满了之后,首先删除的是最近最不常用的图片,此时的引用为WeakReference。具体实现如下:
private final Map<String, Bitmap> lruCache = Collections.synchronizedMap(new LinkedHashMap(10, 1.1F, true));//设定初始容量为10,加载因子为1.1,按访问顺序排序的Map。 protected Bitmap removeNext() { Bitmap mostLongUsedValue = null; synchronized (this.lruCache) { Iterator it = this.lruCache.entrySet().iterator(); if (it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); mostLongUsedValue = (Bitmap)entry.getValue(); it.remove(); } } return mostLongUsedValue; }
LargestLimitedMemoryCache 对应是按存储大小进行删除的缓存策略,即当图片缓存满了之后,对Map进行遍历,首先删除的占用存储空间最大的图片,此时的引用为WeakReference。具体实现如下:
protected Bitmap removeNext() { Integer maxSize = null; Bitmap largestValue = null; Set entries = this.valueSizes.entrySet(); synchronized (this.valueSizes) { for (Map.Entry entry : entries) { if (largestValue == null) { largestValue = (Bitmap)entry.getKey(); maxSize = (Integer)entry.getValue(); } else { Integer size = (Integer)entry.getValue(); if (size.intValue() > maxSize.intValue()) { maxSize = size; largestValue = (Bitmap)entry.getKey(); } } } } this.valueSizes.remove(largestValue); return largestValue; }
UsingFreqLimitedMemoryCache对应是按使用次数多少进行删除的缓存策略,即当图片缓存满了之后,对Map进行遍历,首先删除的是使用次数最少的图片,此时的引用为WeakReference。具体实现如下:
protected Bitmap removeNext() { Integer minUsageCount = null; Bitmap leastUsedValue = null; Set entries = this.usingCounts.entrySet(); synchronized (this.usingCounts) { for (Map.Entry entry : entries) { if (leastUsedValue == null) { leastUsedValue = (Bitmap)entry.getKey(); minUsageCount = (Integer)entry.getValue(); } else { Integer lastValueUsage = (Integer)entry.getValue(); if (lastValueUsage.intValue() < minUsageCount.intValue()) { minUsageCount = lastValueUsage; leastUsedValue = (Bitmap)entry.getKey(); } } } } this.usingCounts.remove(leastUsedValue); return leastUsedValue; }
4、查看FuzzyKeyMemoryCache 和LimitedAgeMemoryCache 类
FuzzyKeyMemoryCache 在put的时候,会先删除具有相同意义的key,然后再添加,具体实现如下:
public boolean put(String key, Bitmap value) { synchronized (this.cache) { String keyToRemove = null; for (String cacheKey : this.cache.keys()) { if (this.keyComparator.compare(key, cacheKey) == 0) { keyToRemove = cacheKey; break; } } if (keyToRemove != null) { this.cache.remove(keyToRemove); } } return this.cache.put(key, value); }
LimitedAgeMemoryCache对应最大有效时限的缓存策略,在put的时候,存储当前时间戳,在get的时候会判断当前元素的存储时限是否大于最大时限,如果大于,获取之后则直接删除,具体实现如下:
public Bitmap get(String key) { Long loadingDate = (Long)this.loadingDates.get(key); if ((loadingDate != null) && (System.currentTimeMillis() - loadingDate.longValue() > this.maxAge)) { this.cache.remove(key); this.loadingDates.remove(key); } return this.cache.get(key); }
5、查看LruMemoryCache
LruMemoryCache 有缓存存储的最大容量上限,put时,如果key之前有对应的value,在计算当前使用的容量时,需要先减去之前value的大小,再加上新的value的大小。同时,删除最老的键值对,直到剩下的键值对的总值少于或者等于标准最大值,具体实现如下:
public final boolean put(String key, Bitmap value) { if ((key == null) || (value == null)) { throw new NullPointerException("key == null || value == null"); } synchronized (this) { this.size += sizeOf(key, value); Bitmap previous = (Bitmap)this.map.put(key, value); if (previous != null) { this.size -= sizeOf(key, previous); } } trimToSize(this.maxSize); return true; }
private void trimToSize(int maxSize) { while (true) synchronized (this) { if ((this.size < 0) || ((this.map.isEmpty()) && (this.size != 0))) { throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!"); } if ((this.size <= maxSize) || (this.map.isEmpty())) { break; } Map.Entry toEvict = (Map.Entry)this.map.entrySet().iterator().next(); if (toEvict == null) { break; } String key = (String)toEvict.getKey(); Bitmap value = (Bitmap)toEvict.getValue(); this.map.remove(key); this.size -= sizeOf(key, value); } }
同时,我们在这里特殊说明下,UniversalImageLoader默认的内存缓存模式就是这个,缓存的是bitmap的强引用,其调用方式在DefaultConfigurationFactory:
public static MemoryCache createMemoryCache(Context context, int memoryCacheSize) { if (memoryCacheSize == 0) { ActivityManager am = (ActivityManager)context.getSystemService("activity"); int memoryClass = am.getMemoryClass(); if ((hasHoneycomb()) && (isLargeHeap(context))) { memoryClass = getLargeMemoryClass(am); } memoryCacheSize = 1048576 * memoryClass / 8; } return new LruMemoryCache(memoryCacheSize); }
- UniversalImageLoader源码学习——LruMemoryCache内存缓存
- UniversalImageLoader源码解读04-内存缓存
- UniversalImageLoader源码解读05-磁盘缓存
- UniversalImageLoader源码解读07-内存泄漏和bug
- UniversalImageLoader加密磁盘缓存
- UniversalImageLoader 源码笔记(1)
- universal image loader源码分析——图片内存缓存
- universalImageLoader为什么使用缓存技术
- UniversalImageLoader——异步加载图片
- Android图片加载框架——UniversalImageLoader
- Android图片加载框架——UniversalImageLoader
- Universal-Image-Loader源码阅读(15)-memory/impl/LruMemoryCache
- 【AndroidUniversalImageLoader】源码学习之缓存模块(磁盘缓存,内存缓存)
- UniversalImageLoader源码解析之 DiskCache
- UniversalImageLoader源码解析之 MomoryCache
- nginx源码学习——内存池
- UniversalImageLoader
- UniversalImageLoader
- SSH整合中在Hibernate不能自动创建表的问题
- Leetcode 32. Longest Valid Parentheses (Hard) (cpp)
- File "E:\python27\lib\site-packages\pytesser\pytesser.py",出错
- 关于java中parseInt的一个趣事
- Retrofit提交参数
- UniversalImageLoader源码学习——LruMemoryCache内存缓存
- Android FoldingLayout 折叠布局 原理及实现(二)
- HDU 1698 Just a Hook
- Java线程的同步
- 继承
- 基于shopxx开源项目页面原型,做的完全个人实现的shop--项目
- Spring学习总结
- Tomcat 启动两次的问题(ServletContextListener的contextInitialized被执行两次的问题)
- Android 打造炫目的圆形菜单 秒秒钟高仿建行圆形菜单