Glide分为内存缓存和硬盘缓存两种
内存缓存默认开启,使用的算法是LruCache算法(Least Recently Used),最近最少使用算法。主要原理是对象的强引用存储在LinkedHashMap中,达到预设定的值淘汰最近最少使用的对象,除了Lru外还结合了弱引用。
下面来看下源码
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
// 通过 skipMemoryCache() 设置
return null;
}
// 对于不同的key 获取不同的缓存 获取后从缓存中删除
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
// 获得缓存后 存储弱引用Map中 保护不会被LruCache回收掉
cached.acquire();
activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
}
return cached;
}
那这个缓存是什么时候写进去的?当然是从网络获取后存进去,之前文章分析的handleResultOnMainThread
方法。
private void handleResultOnMainThread() {
if (isCancelled) {
resource.recycle();
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received a resource without any callbacks to notify");
}
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
engineResource.acquire();
listener.onEngineJobComplete(key, engineResource);
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource);
}
}
engineResource.release();
}
在onEngineJobComplete方法里进行了缓存
public void onEngineJobComplete(Key key, EngineResource<?> resource) {
Util.assertMainThread();
// A null resource indicates that the load failed, usually due to an exception.
if (resource != null) {
resource.setResourceListener(key, this);
if (resource.isCacheable()) {
activeResources.put(key, new ResourceWeakReference(key, resource, getReferenceQueue()));
}
}
jobs.remove(key);
}
在上面代码可以看出 缓存先放在了弱引用map中,engineResource.acquire()会对EngineResource的引用计数+1 ,release会对计数-1,当计数=0的时候在LruCache里,当计数大于1的时候在弱引用中,在release的时候会进行判断,计数=0的时候会放入到LruCache中
void release() {
if (acquired <= 0) {
throw new IllegalStateException("Cannot release a recycled or not yet acquired resource");
}
if (!Looper.getMainLooper().equals(Looper.myLooper())) {
throw new IllegalThreadStateException("Must call release on the main thread");
}
if (--acquired == 0) {
// 在这放入LruCache中
listener.onResourceReleased(key, this);
}
}
再来看下硬盘缓存
private Resource<T> loadFromCache(Key key) throws IOException {
File cacheFile = diskCacheProvider.getDiskCache().get(key);
if (cacheFile == null) {
return null;
}
Resource<T> result = null;
try {
result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
} finally {
if (result == null) {
diskCacheProvider.getDiskCache().delete(key);
}
}
return result;
}
那么硬盘缓存是怎么写入的呢? 没有缓存的时候调用decodeFromSource(
public Resource<Z> decodeFromSource() throws Exception {
Resource<T> decoded = decodeSource();
return transformEncodeAndTranscode(decoded);
}
private Resource<T> decodeSource() throws Exception {
Resource<T> decoded = null;
try {
long startTime = LogTime.getLogTime();
final A data = fetcher.loadData(priority);
if (isCancelled) {
return null;
}
decoded = decodeFromSourceData(data);
} finally {
fetcher.cleanup();
}
return decoded;
}
private Resource<T> decodeFromSourceData(A data) throws IOException {
final Resource<T> decoded;
if (diskCacheStrategy.cacheSource()) {
decoded = cacheAndDecodeSourceData(data);
} else {
long startTime = LogTime.getLogTime();
decoded = loadProvider.getSourceDecoder().decode(data, width, height);
}
return decoded;
}
private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
long startTime = LogTime.getLogTime();
SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data);
diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
startTime = LogTime.getLogTime();
Resource<T> result = loadFromCache(resultKey.getOriginalKey());
return result;
}
先调用fetcher的loadData()方法读取图片数据,然后调用decodeFromSourceData()方法来对图片进行解码。接下来会判断是否允许缓存原始图片,如果允许的话又会调用cacheAndDecodeSourceData()方法。而在这个方法中同样调用了getDiskCache()方法来获取DiskLruCache实例,接着调用它的put()方法就可以写入硬盘缓存。
总结:
Glide还在缓存的顺序:内存缓存(LruCache缓存和弱引用缓存靠计数转换)->硬盘缓存->网络请求