ImageLoader源码解析(二) 缓存实现
来源:互联网 发布:工厂下单软件 编辑:程序博客网 时间:2024/05/16 14:16
ImageLoader源码解析(二) 缓存实现
1 缓存类的初始化
在ImageLoaderConfiguration.Build中,有内存缓存和硬盘缓存的设置方法
一般来说,如果咱们没有设置自己的缓存实现类的话,会走下面这个方法
- ImageLoaderConfiguration.Builder#initEmptyFieldsWithDefaultValues
private void initEmptyFieldsWithDefaultValues() { //创建默认硬盘缓存 if (diskCache == null) { if (diskCacheFileNameGenerator == null) { diskCacheFileNameGenerator = DefaultConfigurationFactory.createFileNameGenerator(); } diskCache = DefaultConfigurationFactory .createDiskCache(context, diskCacheFileNameGenerator, diskCacheSize, diskCacheFileCount); } /** * 创建默认内存缓存 */ if (memoryCache == null) { memoryCache = DefaultConfigurationFactory.createMemoryCache(context, memoryCacheSize); } if (denyCacheImageMultipleSizesInMemory) { //如果需要缓存多种尺寸 memoryCache = new FuzzyKeyMemoryCache(memoryCache, MemoryCacheUtils.createFuzzyKeyComparator()); } }
从上面就可以看出,如果没有设置自己的缓存类,那么Imagloader会通过DefaultConfigurationFactory帮我们创建一个默认的实现类.项目中的代码我已经加上注释,这里就不再书写太多的代码- DefaultConfigurationFactory /** * 创建默认的硬盘缓存 */ public static DiskCache createDiskCache(Context context, FileNameGenerator diskCacheFileNameGenerator, long diskCacheSize, int diskCacheFileCount) { File reserveCacheDir = createReserveDiskCacheDir(context); if (diskCacheSize > 0 || diskCacheFileCount > 0) { //获取缓存文件夹 File individualCacheDir = StorageUtils.getIndividualCacheDirectory(context); try { return new LruDiskCache(individualCacheDir, reserveCacheDir, diskCacheFileNameGenerator, diskCacheSize, diskCacheFileCount); } catch (IOException e) { L.e(e); // continue and create unlimited cache } } File cacheDir = StorageUtils.getCacheDirectory(context); return new UnlimitedDiskCache(cacheDir, reserveCacheDir, diskCacheFileNameGenerator); } /** * 创建默认硬盘缓存文件夹 */ private static File createReserveDiskCacheDir(Context context) { File cacheDir = StorageUtils.getCacheDirectory(context, false); File individualDir = new File(cacheDir, "uil-images"); if (individualDir.exists() || individualDir.mkdir()) { cacheDir = individualDir; } return cacheDir; } /** * 默认内存缓存类 * Creates default implementation of {@link MemoryCache} - {@link LruMemoryCache}<br /> * Default cache size = 1/8 of available app memory. */ 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类进行解析,其他的相差不大#### 2 MemoryCache先看一下抽闲接口MemoryCachepublic interface MemoryCache { /** * Puts value into cache by key * * @return <b>true</b> - if value was put into cache successfully, <b>false</b> - if value was <b>not</b> put into * cache */ boolean put(String key, Bitmap value); /** Returns value by key. If there is no value for key then null will be returned. */ Bitmap get(String key); /** Removes item by key */ Bitmap remove(String key); /** Returns all keys of cache */ Collection<String> keys(); /** Remove all items from cache */ void clear();}
很简单,关键方法 put和get,操作就像map一样,其实内部就是一个map#### 3 LruMemoryCache- lru 算法 参考:http://flychao88.iteye.com/blog/1977653- LinkedHashMap 参考:http://www.cnblogs.com/hubingxu/archive/2012/02/21/2361281.htmlLru应该算是很常用的算法了吧,特别是对于缓存这方便来说Lru缓存,一句话,常用的不会被丢弃,不常用的会被丢弃public class LruMemoryCache implements MemoryCache { /** * 缓存存储map */ private final LinkedHashMap<String, Bitmap> map; /** * 最大缓存值 */ private final int maxSize; /** * 缓存大小,单位字节 */ private int size; /** * @param maxSize Maximum sum of the sizes of the Bitmaps in this cache */ public LruMemoryCache(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } this.maxSize = maxSize; this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true); } /** * 获取缓存的bitmap * Returns the Bitmap for {@code key} if it exists in the cache. If a Bitmap was returned, it is moved to the head * of the queue. This returns null if a Bitmap is not cached. */ @Override public final Bitmap get(String key) { if (key == null) { throw new NullPointerException("key == null"); } synchronized (this) { //LinkHaskMap不是线程安全的 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) { size += sizeOf(key, value); //移除旧的数据 Bitmap previous = map.put(key, value); if (previous != null) { size -= sizeOf(key, previous); } } trimToSize(maxSize); return true; } /** * 控制大小的方法 * Remove the eldest entries until the total of remaining entries is at or below the requested size. * * @param maxSize the maximum size of the cache before returning. May be -1 to evict even 0-sized elements. */ 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); } } } /** * Removes the entry for {@code key} if it exists. */ @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; } } @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 } /** * Returns the size {@code Bitmap} in bytes. * <p/> * An entry's size must not change while it is in the cache. */ 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); }}
注释已经很详细了,其实硬盘缓存也差不多,只是多了文件夹和IO上的一些处理,没有什么本质的区别#### 4 硬盘缓存在com.nostra13.universalimageloader.cache.disc.impl.ext包下有几个扩展缓存类,有兴趣可以看一下5 查询时机
其实在display过程中,有很多次对缓存的查询,下面我一一列出来,就不再粘贴代码了
- ImageLoader.displayImage()方法中第一次内存查找(同步)
- LoadAndDisplayImageTask.run方法第二次内存查找(异步)
- LoadAndDisplayImageTask.tryLoadBitmap方法第一次硬盘查找(异步)
- 网络加载图片(异步)
参考
1 LinkedHashMap
- 顺序排序
//默认是按插入顺序排序,
// 如果指定按访问顺序排序,那么调用get方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。
// 可以重写removeEldestEntry方法返回true值指定插入元素时移除最老的元素。
- 负荷系数
如果负载因子是0.75,hashmap(16)最多可以存储12个元素,想存第16个就得扩容成32。
如果负载因子是1,hashmap(16)最多可以存储16个元素。
同样存16个元素,一个占了32个空间,一个占了16个空间的内存。
实际容量 = 最大容量 * 负载因子,如果最大容量不变的情况下增大负载因子,当然可以增加实际容量,如果负载因子大了会增加哈希冲突发生的概率
阅读全文
0 0
- ImageLoader源码解析(二) 缓存实现
- ImageLoader硬盘缓存解析
- ImageLoader内存缓存解析
- Universal-ImageLoader源码解析
- ImageLoader源码解析
- ImageLoader 源码解析
- ImageLoader源码解析(一)
- ImageLoader源码解析-----ImageLoader的结构
- ImageLoader源码解析(四) 补充 Displayer的实现
- ImageLoader使用及源码解析
- ImageLoader实现Bitmap三级缓存
- 巩固缓存相关,深入解析imageLoader
- Android-Universal-Imageloader源码完全解析
- ImageLoader源码解析(三) 线程调度
- android图片缓存实现(自定义ImageLoader)
- 笔记---ImageLoader实现图片压缩,缓存
- ImageLoader框架实现的图片缓存
- ImageLoader三级缓存实现简单分析
- LARC DL笔记(五):pysol toolbox
- 我的oracle数据库旅程
- UE4 美术学习笔记和经验
- 数组的中length的理解
- Hadoop踩坑
- ImageLoader源码解析(二) 缓存实现
- java多线程之死锁
- Python乱码问题
- 《算法图解》的二分查找的java和python实现
- jsp地址栏传参乱码解决方法2
- B
- JAVA基础(二)
- mysql函数之substr 注意脚标从1开始
- 欢迎使用CSDN-markdown编辑器