前言
在上一篇文章中介绍了Glide基本的调用流程,总结起来就是Engine
是真正加载资源的入口,SingleRequest
起到连接RequestManager
、Target
和Engine
的纽带关系,本文将承接上文,探讨Glide的加载流程。
本章要讨论的内容:
- Engine的工作流程;
- 内存缓存ActiveResource原理剖析;
- 内存缓存MemoryCache原理剖析;
- EngineJob缓存分析;
- EngineJob和DecodeJob的工作原理;
在讨论Engine之前,还是从调用它的地方开始SingleReques.onSizeReady
从Engine开始
SingleRequest.java
@Override
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
if (IS_VERBOSE_LOGGABLE) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
if (IS_VERBOSE_LOGGABLE) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
//创建Engine对象
loadStatus = engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this);//最后一个this是回调接口
// have completed asynchronously.
if (status != Status.RUNNING) {
loadStatus = null;
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
复制代码
Engine.load()方法有很多参数,其中大部分是从requestOptions中获得,值得注意的是最后一个参数ResourceCallback
,,由于Engine的缓存加载逻辑是异步的,所以SingleRequest得到Engine的结果就全在实现方法onResourceReady()
和onLoadFailed()
里了;SingleRequest的回调不再讲解,我们要往底层探索,从Engine这个类开始;注意,Engine.load()的调用还在主线程中;
Engine的初始化和加载流程
Engine.java
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
private final Jobs jobs;
private final MemoryCache cache;
private final EngineJobFactory engineJobFactory;
private final ResourceRecycler resourceRecycler;
private final LazyDiskCacheProvider diskCacheProvider;
private final DecodeJobFactory decodeJobFactory;
private final ActiveResources activeResources;
//构造方法
Engine(MemoryCache cache,
DiskCache.Factory diskCacheFactory,
GlideExecutor diskCacheExecutor,
GlideExecutor sourceExecutor,
GlideExecutor sourceUnlimitedExecutor,
GlideExecutor animationExecutor,
Jobs jobs,
EngineKeyFactory keyFactory,
ActiveResources activeResources,
EngineJobFactory engineJobFactory,
DecodeJobFactory decodeJobFactory,
ResourceRecycler resourceRecycler,
boolean isActiveResourceRetentionAllowed) {
this.cache = cache;
//创建diskCacheProvider
this.diskCacheProvider = new LazyDiskCacheProvider(diskCacheFactory);
//创建activeResources
if (activeResources == null) {
activeResources = new ActiveResources(isActiveResourceRetentionAllowed);
}
this.activeResources = activeResources;
//监听
activeResources.setListener(this);
//创建EngineKeyFactory()
if (keyFactory == null) {
keyFactory = new EngineKeyFactory();
}
this.keyFactory = keyFactory;
//创建Jobs
if (jobs == null) {
jobs = new Jobs();
}
this.jobs = jobs;
//创建engineJobFactory
if (engineJobFactory == null) {
engineJobFactory =
new EngineJobFactory(
diskCacheExecutor, sourceExecutor, sourceUnlimitedExecutor, animationExecutor, this);
}
this.engineJobFactory = engineJobFactory;
//创建decodeJobFactory
if (decodeJobFactory == null) {
decodeJobFactory = new DecodeJobFactory(diskCacheProvider);
}
this.decodeJobFactory = decodeJobFactory;
//创建resourceRecycler
if (resourceRecycler == null) {
resourceRecycler = new ResourceRecycler();
}
this.resourceRecycler = resourceRecycler;
//监听
cache.setResourceRemovedListener(this);
}
public <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) {
Util.assertMainThread();
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
//获得key
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//从当前正在使用的Resources里面去
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
//如果命中,直接回调结果
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
//返回null
return null;
}
//从内存缓存中获取
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
//如果命中,直接回调结果
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
//返回null
return null;
}
//以上都没有命中,试图从已存在的任务中对应的EngineJob
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
//如果去到,把cb往下传递
current.addCallback(cb);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
//返回结果
return new LoadStatus(cb, current);
}
//取不到创建下新的EngineJob
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
//创建新的DecodeJob
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
//将当前的engineJob添加到缓存中
jobs.put(key, engineJob);
//回调往下传递
engineJob.addCallback(cb);
//engineJob开始执行
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
}
复制代码
在Engine的构造方法中,创建了默认的各种factory和容器,诸如engineJobFactory
、decodeJobFactory
和Jobs
、activeResources
等,各种参数先不一一介绍,我们看load()方法,这是整个调用的出发点;我在代码中已经注释的很清晰,下面再梳理一遍流程:
load流程
- 通过keyFactory和请求参数,创建EngineKey对象key;
- 调用
loadFromActiveResources()
方法,尝试从活动的Resources中获取active; - 如果步骤2命中,直接回调cb.onResourceReady(),并返回,不命中,执行步骤4;
- 调用
loadFromCache()
方法,尝试从内存缓存中获取cached; - 如果步骤4命中,直接回调cb.onResourceReday(),并返回,不命中,执行步骤6;
- 尝试从jobs中获取匹配key的正在执行的EngineJob current;
- 如果步骤6命中,把回调添加到current并返回,不命中,执行步骤8;
- 通过engineJobFactory创建新的EngineJob对象engineJob;
- 根据decodeJobFactory创建新的DecodeJob对象decodeJob;
- 把engineJob添加进jobs中,讲回调cb设置到engineJob中;
- 执行engineJob.start(decodeJob);
接下来我们从loadFromActiveResources开始,分析感兴趣的方法
loadFromActiveResources流程
Engine.java
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
复制代码
ActiveResource的要从activeResources中获取,activeResources在Engine构造方法中创建,我们分析ActiveResource类的简单实现;
ActiveResource.java
final class ActiveResources {
private static final int MSG_CLEAN_REF = 1;
final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
private ReferenceQueue<EngineResource<?>> resourceReferenceQueue;
private Thread cleanReferenceQueueThread;
private ResourceListener listener;//一般engine监听次方法
//缓存的复用在主线程中执行
private final Handler mainHandler = new Handler(Looper.getMainLooper(), new Callback() {
@Override
public boolean handleMessage(Message msg) {
if (msg.what == MSG_CLEAN_REF) {
cleanupActiveReference((ResourceWeakReference) msg.obj);
return true;
}
return false;
}
});
//设置监听
void setListener(ResourceListener listener) {
this.listener = listener;
}
//get方法
EngineResource<?> get(Key key) {
ResourceWeakReference activeRef = activeEngineResources.get(key);
if (activeRef == null) {
return null;
}
EngineResource<?> active = activeRef.get();
if (active == null) {
cleanupActiveReference(activeRef);
}
return active;
}
//activate方法,相当于put
void activate(Key key, EngineResource<?> resource) {
ResourceWeakReference toPut =
new ResourceWeakReference(
key,
resource,
getReferenceQueue(),
isActiveResourceRetentionAllowed);
ResourceWeakReference removed = activeEngineResources.put(key, toPut);
if (removed != null) {
removed.reset();//移除的弱引用对象需要清除强引用
}
}
//清除当前被GC的ref对象
void cleanupActiveReference(@NonNull ResourceWeakReference ref) {
Util.assertMainThread();
activeEngineResources.remove(ref.key);//从集合中移除掉
if (!ref.isCacheable || ref.resource == null) {
return;
}
//创建新的对象EngineResource,复用ref.resource,
EngineResource<?> newResource =
new EngineResource<>(ref.resource, /*isCacheable=*/ true, /*isRecyclable=*/ false);
newResource.setResourceListener(ref.key, listener);
listener.onResourceReleased(ref.key, newResource);
}
//创建resourceReferenceQueue,用来监听垃圾回收对象
if (resourceReferenceQueue == null) {
resourceReferenceQueue = new ReferenceQueue<>();
//创建线程监听弱引用回收对列
cleanReferenceQueueThread = new Thread(new Runnable() {
@SuppressWarnings("InfiniteLoopStatement")
@Override
public void run() {
//设置线程优先级有后台线程
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
cleanReferenceQueue();
}
}, "glide-active-resources");
cleanReferenceQueueThread.start();
}
return resourceReferenceQueue;
}
//shutdown中断线程,清除队列
void shutdown() {
isShutdown = true;
if (cleanReferenceQueueThread == null) {
return;
}
cleanReferenceQueueThread.interrupt();
try {
cleanReferenceQueueThread.join(TimeUnit.SECONDS.toMillis(5));
if (cleanReferenceQueueThread.isAlive()) {
throw new RuntimeException("Failed to join in time");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
//清除回收对象
@Synthetic void cleanReferenceQueue() {
while (!isShutdown) {
try {
ResourceWeakReference ref = (ResourceWeakReference) resourceReferenceQueue.remove();
mainHandler.obtainMessage(MSG_CLEAN_REF, ref).sendToTarget();
// This section for testing only.
DequeuedResourceCallback current = cb;
if (current != null) {
current.onResourceDequeued();
}
// End for testing only.
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
//弱引用监听对象,强引用保存真正的资源
static final class ResourceWeakReference extends WeakReference<EngineResource<?>> {
@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);
//保存key
this.key = Preconditions.checkNotNull(key);
//保存resource,强引用
this.resource =
referent.isCacheable() && isActiveResourceRetentionAllowed
? Preconditions.checkNotNull(referent.getResource()) : null;
isCacheable = referent.isCacheable();
}
//清除强引用
void reset() {
resource = null;
clear();
}
}
}
复制代码
ActiveResource缓存原理
ActiveResources采用HashMap+WeakRefence方式保存EngineResource对象,没有对集合size做限制,在使用WeakReference的时候,创建了一个ReferenceQueue,来记录被GC回收的EngineResource对象,而且在创建ReferenceQueue时生成了一个后台线程cleanReferenceQueueThread,不断地执行cleanReferenceQueue()
方法,一旦ReferenceQueue取出不为空,便取出ref对象,执行cleanupActiveReference()
方法
有必要看一下EngineResource类结构:
EngineResource.java
class EngineResource<Z> implements Resource<Z> {
private final boolean isCacheable;
private final boolean isRecyclable;
private ResourceListener listener;
private Key key;
private int acquired;
private boolean isRecycled;
private final Resource<Z> resource;//真正的resource
interface ResourceListener {
void onResourceReleased(Key key, EngineResource<?> resource);
}
EngineResource(Resource<Z> toWrap, boolean isCacheable, boolean isRecyclable) {
resource = Preconditions.checkNotNull(toWrap);
this.isCacheable = isCacheable;
this.isRecyclable = isRecyclable;
}
void setResourceListener(Key key, ResourceListener listener) {
this.key = key;
this.listener = listener;
}
Resource<Z> getResource() {
return resource;
}
}
复制代码
本质上EngineResource是对Resource的包装类,所以下面的gc分析一定要区分EngineResource
和Resource
,这俩不是一个对象;
牛掰的弱引用复用机制
ResourceWeakReference这个类不简单,它本意是对EngineResource的弱引用,其实在构造它时候,会把EngineResource.resource和EngineResource.key以强引用的形式保存,所以垃圾回收的是EngineResource,却回收不掉EngineResource.resource,因为此时resource会被ResourceWeakReference引用;
cleanupActiveReference()
首先取出ref.resource,这个对象是强引用,不会被回收,被回收的是ref包装的EngineResource;然后创建新的EngineResource包装真正的resource,最终调用资源回收的监听listener.onResourceReleased(ref.key, newResource)
,而setListener()
在Engine
构造方法中调用;看一下Engine.onResourceReleased()方法的实现:
Engine.java
public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
Util.assertMainThread();
//把key对应的ResourceWeakReference从Map中移除
activeResources.deactivate(cacheKey);
if (resource.isCacheable()) {
//内存缓存复用
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource);
}
}
复制代码
Engine在onResourceReleased
时,重新保存了EngineResource对象,并且在此之前,还调用了activeResources.deactivate(cacheKey);
为什么要deactivate,下面解释一下原因:
因为在ActiveResources.cleanupActiveReference()
中创建新的EngineResource来包装被回收的EngineResource下面的resource,但是这个resource还在被ref强引用,所以执行activeResources.deactivate(cacheKey)
会清除ref多resource的强引用;
弄明白了这些,ActiveResources原理基本上搞明白了;
小结:
ActiveResources
采用弱引用的方式,记录EngineResource
的回收情况,同时采取强引用保存EngineResource.resource
,在ActiveResources
中会有个后台线程会执行清理工作,一旦发现某个EngineResource
被回收,就会拿出其对应的resource
,然后创建一个新的EngineResource
包装这个resource
,之后回调给Engine
,让其做内存缓存,最后Engine
调用activeResources.deactivate(cacheKey)
解除ref
对resource
强引用。
loadFromCache()流程分析
未完待续睡觉...