本篇文章涉及EngineKey、EngineResource、ActiveResource、LruResourceCache类。
通过分析SingleRequest的源码我们知道,图片的加载是从Engine.load()开始:
public synchronized <R> LoadStatus load(
GlideContext glideContext, Object model, Key signature, int width, int height, Class<?> resourceClass, Class<R> transcodeClass, Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor) {
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
return null;
}
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
return null;
}
先说一下,SingleRequest中的成员变量engine是在Glide初始化的时候生成的实例,然后作为参数不断传递到SingleRequest中。
一、EngineKey
首先生成一个EngineKey,EngineKey实现了Key接口,内部重写了equals()方法,当model、signature、width、height、transformations、resourceClass、transcodeClass、options都相等时才认为是同一个EngineKey。EngineKey的生成用了简单工厂方法,实现在EngineKeyFactory类,该类就一个方法,不知道为何不直接写到EngineKey类里面,非得创建一个类。也可以看到Glide很多地方创建对象都用了简单工厂方法
EngineKey buildKey(Object model, Key signature, int width, int height,
Map<Class<?>, Transformation<?>> transformations, Class<?> resourceClass, Class<?> transcodeClass, Options options) {
return new EngineKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options);
}
EngineKey重写了Key的updateDiskCacheKey()方法,不过里面的实现是抛出了异常,这个还没有看懂,TODO
@Override
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
throw new UnsupportedOperationException();
}
二、EngineResource
实现了Resource<Z>接口,同时有几个成员变量记录状态:isCacheable、isRecyclable、key、isRecycled;
三、ActiveResource
根据EngineKey去查找有没有存在的ActivityResource,如果有则回调onResourceReady(active, DataSource.MEMORY_CACHE),并返回空;
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
其中activeResource是在Engine初始化的时候创建的,是Glide的第一级缓存,表示当前正在使用的资源,当下一级资源中获取到资源时会加入ActivityResource,当资源不再使用时会移除,因此该缓存中的资源生命周期较短,没有内存大小限制。
ActiveResource是一个管理类,内部有成员变量 Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>(); 以EngineKey为Key保存着活跃资源的弱引用;ResourceWeakReference继承了WeakReference<EngineResource<?>>,且传入了 ReferenceQueue<EngineResource<?>> resourceReferenceQueue 来接收回收信号。同时创建了一个单线程池运行一个Runnable,Runnable中死循环不断监听被回收的资源引用,被回收的资源引用对应的key需要从activeEngineResources中移除,且通知外部listener(其实就是Engine本身)有资源被移除了:
void cleanupActiveReference(@NonNull ResourceWeakReference ref) {
// Fixes a deadlock where we normally acquire the Engine lock and then the ActiveResources lock
// but reverse that order in this one particular test. This is definitely a bit of a hack...
synchronized (listener) {
synchronized (this) {
activeEngineResources.remove(ref.key);
if (!ref.isCacheable || ref.resource == null) {
return;
}
EngineResource<?> newResource = new EngineResource<>(ref.resource, /*isCacheable=*/ true, /*isRecyclable=*/ false);
newResource.setResourceListener(ref.key, listener);
listener.onResourceReleased(ref.key, newResource);
}
}
}
@Synthetic void cleanReferenceQueue() {
while (!isShutdown) {
try {
ResourceWeakReference ref = (ResourceWeakReference) resourceReferenceQueue.remove(); //死循环接收要回收的资源引用;
cleanupActiveReference(ref);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
四、LruResourceCache
当在ActiveResource中没有找到key对应的资源时,就会去engine的cache中找,cache是LruResourceCache的实例。LruResourceCache继承自LruCache,用到了近期最少使用算法,这个后面单独写一篇来讲。
在cache中找到Key对应的资源则回调onResourceReady(active, DataSource.MEMORY_CACHE),并返回空;同时需要将该资源加入ActiveResource,因为这个资源即将被使用。
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(); //如果之前有key对应的旧资源引用需要清除之;
}
}
如果资源在ActiveResource、LruResourceCache中都没有找到,那么就需要去获取,Glide维护了一个EngineJob类来负责获取资源。
接下来就需要另写一篇文章来分析EngineJob了。