阅读本篇文章,建议先阅读:
Glide解析一:Glide整体流程
在分析Glide的整体流程时,我们知道Glide有三级缓存策略,一个是活跃内存缓存,一个是内存缓存,一个是磁盘缓存。这边文章将对活跃内存缓存策略进行剖析。
在Glide整体流程分析知道ActiveResources的活跃内存缓存的实现,我们从这个类进行入手:
ActiveResources的核心就是维护一个Map,这个map就是维系图片包装类弱引用的:
final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
ResourceWeakReference继承了WeakReference:
static final class ResourceWeakReference extends WeakReference<EngineResource<?>> {
//关联的key
@SuppressWarnings("WeakerAccess") @Synthetic final Key key;
//是否可缓存
@SuppressWarnings("WeakerAccess") @Synthetic final boolean isCacheable;
//关联的图片资源
@Nullable @SuppressWarnings("WeakerAccess") @Synthetic Resource<?> resource;
@Synthetic
@SuppressWarnings("WeakerAccess")
ResourceWeakReference(
@NonNull Key key,
@NonNull EngineResource<?> referent,
@NonNull ReferenceQueue<? super EngineResource<?>> queue,
boolean isActiveResourceRetentionAllowed) {
super(referent, queue);
this.key = Preconditions.checkNotNull(key);
this.resource =
referent.isCacheable() && isActiveResourceRetentionAllowed
? Preconditions.checkNotNull(referent.getResource()) : null;
isCacheable = referent.isCacheable();
}
void reset() {
resource = null;
//清除ResourceWeakReference
clear();
}
}
既然是维系Map,那么从活跃缓存中取图片资源对应的就是get,将图片资源加入活跃缓存中对于的就是put。
我们先看下put的操作:
void activate(Key key, EngineResource<?> resource) {
//将图片资源和关联的key使用弱引用进行包装s关联
ResourceWeakReference toPut =
new ResourceWeakReference(
key,
resource,
getReferenceQueue(),
isActiveResourceRetentionAllowed);
//将包装之后的图片资源弱引用加入map中
ResourceWeakReference removed = activeEngineResources.put(key, toPut);
if (removed != null) {
//移除之前就的图片资源弱引用
removed.reset();
}
}
put的操作没什么,就不废话了,代码中有注释说明
get操作:
EngineResource<?> get(Key key) {
//根据key从map中取出图片资源弱引用
ResourceWeakReference activeRef = activeEngineResources.get(key);
if (activeRef == null) {
//如果图片资源资源弱引用为空,返回空
return null;
}
//从弱引用中获取图片资源
EngineResource<?> active = activeRef.get();
if (active == null) {
//如果图片资源已经释放,则调用cleanupActiveReference清除处理
cleanupActiveReference(activeRef);
}
//返回图片资源
return active;
}
get的操作其实就是从map取出弱引用对象,再从弱引用对象中取出图片资源。这里有个关键的地方cleanupActiveReference,如果配置的图片可缓存,那么这里就会将活跃缓存中的图片资源移除到内存缓存中,我们看下cleanupActiveReference的系列逻辑:
@Synthetic void cleanupActiveReference(@NonNull ResourceWeakReference ref) {
//断言是否在主线程,如果不在主线程则抛出异常
Util.assertMainThread();
//从map中移除key对应的图片资源弱引用对象
activeEngineResources.remove(ref.key);
if (!ref.isCacheable || ref.resource == null) {
//如果图片不可缓存或者图片资源为空,则结束
return;
}
//图片可缓存并且图片资源不为空
//重新包装成EngineResource图片资源对象
EngineResource<?> newResource =
new EngineResource<>(ref.resource, /*isCacheable=*/ true, /*isRecyclable=*/ false);
newResource.setResourceListener(ref.key, listener);
//回调告知图片资源已经从活跃缓存中移除释放
listener.onResourceReleased(ref.key, newResource);
}
这里的listener就是图片加载引擎Engine对象,我们看下图片加载引擎Engine对象的onResourceReleased方法是做什么处理的:
public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
//断言是否在主线程,如果不在主线程则抛出异常
Util.assertMainThread();
//从活跃缓存中移除指定key对应的图片资源
activeResources.deactivate(cacheKey);
if (resource.isCacheable()) {
//图片资源可缓存
//将活跃缓存移除的图片资源加入内存缓存中进行缓存
cache.put(cacheKey, resource);
} else {
//图片资源不可缓存,执行释放操作
resourceRecycler.recycle(resource);
}
}
void deactivate(Key key) {
//从map中删除key对应的图片资源弱引用
ResourceWeakReference removed = activeEngineResources.remove(key);
if (removed != null) {
//清除释放图片资源弱引用
removed.reset();
}
}
综合上述解析,其实活跃缓存策略没什么复杂的,它的核心:
- 使用弱引用对图片资源和key进行包装
- 用HashMap进行管理,key是与图片资源关联的Key,value是经过包装的图片资源弱引用
- put操作就是讲图片资源包装成图片资源弱引用对象,然后放入HashMap中
- get操作就是根据key从HashMap中取出对应的图片资源弱引用对象,再从图片资源弱引用对象中取出图片资源,当弱引用中图片资源为空,如果可缓存则将图片资源缓存到内存缓存中,否则进行回收释放操作
那么什么时候图片会加入活跃缓存中的呢?Glide解析一:Glide整体流程中有比较详细的解析说明,大体就是图片从网络上加载之后,放入磁盘,再从磁盘中经过转换之后就会放入活跃缓存中。