🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## ImageWorker ImageWorker 主要提供的就是 异步 和 缓存 ![](https://img.kancloud.cn/90/9b/909b03517bfc476008590ef5057cbaf3_469x464.png) ### ImageWorker类 这个是加载图片的核心类,建议大家看源代码从这个类看起。它的主要功能是从内存/磁盘缓存中加载图片,或者是从网络上下载。这里第一要使用缓存,第二从网络上下载,必然要使用异步线程,所以这里从类图中大家也可以看到它有两个关联类 BitmapWorkerTask(继承自AsynTask)和ImageCache, 分别用来处理异步和缓存。 ImageWorker提供给外部的主要接口是loadImage方法 - 加载图片,如果内存中有,直接加载。否则使用异步线程(BitmapWorkerTask)后台加载 - 从磁盘或者是网络上下载 ~~~ public void loadImage(Object data, ImageView imageView) {} ~~~ ### BitmapWorkerTask类 异步处理图片 - 下载并绑定图片 ### ImageCache类 图片的缓存处理,这里使用了二级缓存: 内存和磁盘。这里从类图也可以看到它有一个关联类DiskLruCache。 ### ImageResizer类 继承自ImageWorker,可能有的童鞋会问ImageWorker不是已经实现异步和缓存了吗,这个类是干嘛的呢?这个主要是根据给定的大小对Image做调整。比如当图片太大时,不能简单的加载到内存,需要做大小调整处理。 这里对它的几个主要接口说明一下: * setImageSize:设置图片要调整的大小 * calculateInSampleSize: 计算缩放比例 - 根据原图大小和要调整后的大小计算 * decodeSampledBitmapFrom\*\*\*:得到调整大小后的图片,,这里好几个方法,数据源不一样而已,没啥大区别。 ### ImageFetcher类 继承自ImageResizer。从网络下载图片。这里要澄清一点,processBitmap在ImageWorker中是一个抽象方法,并没有实现体,在本示例中,是在ImageFetcher中实现的。之所以这样设计,是因为图片的来源是不确定和可变的,有可能从网络下载,有可能从本地数据库获取。 ## Universal-Image-Loader ![](https://img.kancloud.cn/6e/a3/6ea3bc91f020bd64998cbed8fea2fed6_1000x745.png) ![](https://img.kancloud.cn/6f/b5/6fb53f92a6631d1842ddbe6561dd76b5_630x1108.png) ## 内存缓存 ### LruCache LinkedHashMap 这个队列到底是由谁来维护的, ![](https://img.kancloud.cn/15/59/15592490eaf8eb1f5bbc1872f433f182_739x390.png) LinkedHashMap 实际上就是hashMap + link 即map里的每个元素增加了前一个引用 和后一个引用 ### 其他内存缓存策略 #### 只使用的是强引用缓存  LruMemoryCache(这个类就是这个开源框架默认的内存缓存类,缓存的是bitmap的强引用,下面我会从源码上面分析这个类) #### 使用强引用和弱引用相结合的缓存 UsingFreqLimitedMemoryCache(如果缓存的图片总量超过限定值,先删除使用频率最小的bitmap) ~~~ private final Map<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>()); //value为使用次数 ~~~ LRULimitedMemoryCache(这个也是使用的lru算法,和LruMemoryCache不同的是,他缓存的是bitmap的弱引用) ~~~ private final Map<String, Bitmap> lruCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(INITIAL_CAPACITY, LOAD_FACTOR, true)); ~~~ FIFOLimitedMemoryCache(先进先出的缓存策略,当超过设定值,先删除最先加入缓存的bitmap) ~~~ private final List<Bitmap> queue = Collections.synchronizedList(new LinkedList<Bitmap>()); ~~~ LargestLimitedMemoryCache(当超过缓存限定值,先删除最大的bitmap对象) ~~~ private final Map<Bitmap, Integer> valueSizes = Collections.synchronizedMap(new HashMap<Bitmap, Integer>()); //value为大小 ~~~ LimitedAgeMemoryCache(当 bitmap加入缓存中的时间超过我们设定的值,将其删除) ~~~ private final Map<String, Long> loadingDates = Collections.synchronizedMap(new HashMap<String, Long>()); //value为时间戳 ~~~ #### 只使用弱引用缓存 WeakMemoryCache(这个类缓存bitmap的总大小没有限制,唯一不足的地方就是不稳定,缓存的图片容易被回收掉) ## 磁盘缓存 ### 获取缓存地址 ~~~ public File getDiskCacheDir(Context context, String uniqueName) { String cachePath; if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { cachePath = context.getExternalCacheDir().getPath(); } else { cachePath = context.getCacheDir().getPath(); } return new File(cachePath + File.separator + uniqueName); ~~~ 可以看到,当SD卡存在或者SD卡不可被移除的时候,就调用getExternalCacheDir()方法来获取缓存路径,否则就调用getCacheDir()方法来获取缓存路径。前者获取到的就是 /sdcard/Android/data//cache 这个路径,而后者获取到的是 /data/data//cache 这个路径。 ### 实际效果 ![](https://img.kancloud.cn/72/f6/72f67fdd50e07bfe9a5c6cf2a8948fa3_250x226.png) 缓存目录有许多个文件名很长的文件,和一个journal文件,那个文件名很长的文件自然就是缓存的图片了,因为是使用了MD5编码来进行命名的。 journal记录了操作,作为管理缓存的手段