Picasso 图片加载库源码分析3-内存缓存
前面说的 OkHttp3Downloader 其实可以理解为磁盘缓存,缓存算法用的是 LRU,这里说的是内存缓存,同样缓存算法用的也是 LRU。
创建 LurCache 对象需要提供缓存大小,这个大小其实跟应用配置有关(即 largeHeap 相关的配置),如果没有配置,默认将是 16 MB 的 15% 左右。
public LruCache(int maxByteCount) {
cache = new android.util.LruCache<String, LruCache.BitmapAndSize>(maxByteCount) {
@Override protected int sizeOf(String key, BitmapAndSize value) {
return value.byteCount;
}
};
}
最后通过该构造方法,创建了一个 Android 自带的 LruCache 类型对象。android.util 包下的这个 LruCache 类型是个泛型类,有点类似 Map,不过其内部本质还真用到了 LinkedHashMap 来维护,从代码上可以知道这个 LruCache 以 String 类型为 key,BitmapAndSize 类型为 value。这个 BitmapAndSize 类型是 picasso 包下面的 LruCache 类里的静态类,内容就像名字一样一个属性是 Bitmap,一个属性是 byteCount。
LRU 算法
插播一个概念介绍 什么是LRU(最近最少使用)算法? 网上一搜一大堆,我觉得这篇理解起来简单,所以引用了。
有了 LRU 概念之后就知道 android.util 包下的 LruCache 实现为什么用到 LinkedHashMap 了。再来看下 Picasso 的 LruCache 几个方法实现,
set
public void set(@NonNull String key, @NonNull Bitmap bitmap) {
int byteCount = Utils.getBitmapBytes(bitmap);
//首先做了一个图片大小的判断
//如果单张图片超过了缓存空间大小,那就不考虑缓存了,
//顺带把缓存里相同的这个 key 的缓存也移除
if (byteCount > maxSize()) {
cache.remove(key);
return;
}
//通过大小检测后就往里放
cache.put(key, new BitmapAndSize(bitmap, byteCount));
}
至于 android.util 包下的 LruCache 的 put 方法逻辑大致是这样的,1.获取将要缓存的资源大小求的当前已缓存的大小,并放入 LinkedHashMap 中,如果 Map 中有相同的 key 值,就会把之前所占的大小减掉。2.重新比对已缓存大小是否超过设定的最大值,如超过,则从 Map 最后一位开始移除,从而腾出一些空间。但感觉这里并没有体现出 LRU 的实现,这个还有待测试验证。
get
@Override public Bitmap get(@NonNull String key) {
//get 方法很简单,通过 key 从 Map 里获取对应 value
//有就返回图片对象,没有就没有了。
BitmapAndSize bitmapAndSize = cache.get(key);
return bitmapAndSize != null ? bitmapAndSize.bitmap : null;
}
还有其他几个方法,
- size 获取当前已缓存的内容大小
- maxSize 获取缓存空间大小
- clear 清空已缓存的内容
- clearKeyUri 清空 key 中含有指定内容的缓存内容