glide的缓存处理
一、内存缓存
在之前的源码分析Engine的load()方法时候,会首先从两个缓存当中加载数据从弱引用中获取缓存数据和从内存缓存中获取缓存数据。
public <R> LoadStatus load(/*各种参数*/) {
// 根据请求参数得到缓存的键
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
// 检查内存中弱引用是否有目标图片
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable); // 1
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
return null;
}
// 检查内存中Lrucache是否有目标图片
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); // 2
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
return null;
}
// ...内存中没有图片构建任务往下执行, 略
return new LoadStatus(cb, engineJob);
}
这里是获取内存缓存数据,那么实在什么时候去保存数据到内存中的呢?
回顾一下这个源码中的notifyCallbacksOfResult()方法在切换回主线程前创建了一个localKey的对象。这就是内存缓存的key对象。
然后调用了listener.onEngineJobComplete(this, localKey, localResource);这是EngineJobListener接口对象。
而Engine对象实现了这个接口。看一下方法中做了什么:
public synchronized void onEngineJobComplete(
EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
// A null resource indicates that the load failed, usually due to an exception.
if (resource != null) {
resource.setResourceListener(key, this);
if (resource.isCacheable()) {
activeResources.activate(key, resource);
}
}
jobs.removeIfCurrent(key, engineJob);
}
resource.setResourceListener(key, this);
这个ResourceListener也是Engine对象实现
public synchronized void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
activeResources.deactivate(cacheKey);
if (resource.isCacheable()) {
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource);
}
}
cache对象就是内存缓存对象。
activeResources.activate(key, resource);
activeResources就是弱引用对象,调用activate方法:
synchronized void activate(Key key, EngineResource<?> resource) {
ResourceWeakReference toPut =
new ResourceWeakReference(
key, resource, resourceReferenceQueue, isActiveResourceRetentionAllowed);
ResourceWeakReference removed = activeEngineResources.put(key, toPut);
if (removed != null) {
removed.reset();
}
}
将资源保存在了弱引用对象中
二、磁盘缓存
首先是 ResourceCacheGenerator,它用来从缓存中得到变换之后数据,在调用它的startNext()方法的时候,会调用helper.getDiskCache().get(currentKey);获取资源数据。从磁盘读取数据的,那么数据又是在哪里向磁盘缓存数据的呢?
当从网络中打开输入流之后会回到 DecodeJob 中,进入下一个阶段,并再次调用 SourceGenerator 的 startNext() 方法。此时会进入到 cacheData() 方法,并将数据缓存到磁盘上,这一块上面没有分析,只是略微提了一下,很简单。
三、Glide 在进行缓存的时候可以缓存转换之后的数据,也可以缓存原始的数据。这个就是在解码完成,转码前有一个回调,回调给DecodeJob。
在DecodeJob.onResourceDecoded() 方法中:
<Z> Resource<Z> onResourceDecoded(DataSource dataSource, Resource<Z> decoded) {
// ... 略
Resource<Z> result = transformed;
boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey);
if (diskCacheStrategy.isResourceCacheable(isFromAlternateCacheKey, dataSource,encodeStrategy)) {
if (encoder == null) {
throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass());
}
final Key key;
// 根据缓存的此略使用不同的缓存的键
switch (encodeStrategy) {
case SOURCE:
key = new DataCacheKey(currentSourceKey, signature);
break;
case TRANSFORMED:
key =
new ResourceCacheKey(
decodeHelper.getArrayPool(),
currentSourceKey,
signature,
width,
height,
appliedTransformation,
resourceSubClass,
options);
break;
default:
throw new IllegalArgumentException("Unknown strategy: " + encodeStrategy);
}
LockedResource<Z> lockedResult = LockedResource.obtain(transformed);
// 将缓存的键和数据信息设置到 deferredEncodeManager 中,随后会将其缓存到磁盘上面
deferredEncodeManager.init(key, encoder, lockedResult);
result = lockedResult;
}
return result;
}
根据缓存的策略构建两种不同的 key,并将其传入到 deferredEncodeManager 中。
然后将会在 DecodeJob 的 notifyEncodeAndRelease() 方法中调用 deferredEncodeManager 的 encode() 方法将数据缓存到磁盘上:
void encode(DiskCacheProvider diskCacheProvider, Options options) {
try {
// 将数据缓存到磁盘上面
diskCacheProvider.getDiskCache().put(key,new DataCacheWriter<>(encoder, toEncode, options));
} finally {
toEncode.unlock();
}
}
这样Glide的缓存原理就介绍完了。