图片加载引擎Engine工作流程
一、Engine 引擎
所有图片加载渠道公用,管理Jobs,load()方法,EngineJob,DecodeJob工厂创建。
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
...
ResourceCallback cb) {
long startTime = LogTime.getLogTime();
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;
}
//开始从磁盘或网络获取
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb);
return new LoadStatus(cb, current);
}
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
...
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
1,内存查找
创建EngineKey,若支持内存缓存,首先,loadFromActiveResources方法,根据key在ActiveResources类中获取资源EngineResource。如果不是空,回调,表示从内存获取,否则继续。其次,loadFromCache方法,根据key从MemoryCache中获取,同样支持内存缓存。
返回的Resource<?>类型,可能是EngineResource,不是则包装一下。将cache返回并加入ActiveResources。如果cache不空,依然回调,否则继续。
以上这两种情况都是从内存获取数据,onResourceReady回调方法表明来源是MEMORY_CACHE。
如果在内存缓存中未找到,需要从磁盘缓存或网络中获取。
2,ResourceCallback回调,SingleRequest实现接口,EngineResource类型,来源如MEMORY_CACHE。
3,每个图片请求建立一个引擎任务EngineJob。承接具体load工作,管理记录Jobs。实现DecodeJob.Callback接口。EngineJob保存cb,开始任务。
根据key在Jobs类,获取EngineJob,存在时,直接LoadStatus返回。
EngineJobFactory和DecodeJobFactory工厂分别创建两个Job,EngineJob和DecodeJob。将EngineJob根据key存储在Jobs类。
4,DecodeJob任务,当任务complete,通知DecodeJob.Callback,回调方法,onResourceReady()。
进一步路由到主线程通知到EngineJob的cb即ResourceCallback。
二、EngineJob
实现DecodeJob.Callback接口,交给DecodeJob,任务complete后通知。
EngineJob的start()方法,启动任务。
GlideExecutor线程池,管理线程任务。
DecodeJob是Runnable任务,该任务可以从资源中,文件缓存,或者网络中获取图片。选择一个合适的线程池。
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
willDecodeFromCache()方法,判断从Disk或Resource缓存中获取,选择合适的线程池执行任务。将DecodeJob任务派发给它。
内部有四个GlideExecutor线程池,均在GlideBuilder中配置。
boolean willDecodeFromCache() {
Stage firstStage = getNextStage(Stage.INITIALIZE);
return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
}
在INITIALIZE状态下,下一个Stage将根据DiskCacheStrategy策略类决定,该类默认的decodeCachedResource方法,允许从资源获取图片,Stage设置RESOURCE_CACHE,如果不允许,再判断decodeCachedData方法,从Disk缓存获取图片,Stage设置DATA_CACHE,两者都不允许时,再次执行getNextStage方法,存在onlyRetrieveFromCache标志,说明只能从缓存,而缓存又不存在,只能结束。否则,Stage设置SOURCE。
当Stage是RESOURCE_CACHE或DATA_CACHE时,从依然是从缓存获取。选择的线程池是diskCacheExecutor,如果Stage是Source状态,选择线程池sourceExecutor。还有animationExecutor和sourceUnlimitedExecutor。针对不同的数据源,线程池不同,影响的是每种数据源线程复用的策略。
三、线程耗时任务
线程运行DecodeJob任务,实现Runnable接口,在非内存获取图片资源时,将该任务分配给适当的线程池,从资源,Disk缓存,或网络中获取。
public void run() {
TraceCompat.beginSection("DecodeJob#run");
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (Throwable t) {
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
} finally {
if (localFetcher != null) {
localFetcher.cleanup();
}
TraceCompat.endSection();
}
}
最终在DecodeJob的notifyComplete方法,通过DecodeJob.Callback回调将数据回复到请求EngineJob中,数据包装Resource<>类型。
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
callback.onResourceReady(resource, dataSource);
}
将资源Resource和数据来源DataSource存储在EngineJob,发送消息到主线程处理,转换资源EngineResource子类。
最后ResourceCallback回调,通知外部load方法传入的cb对象。即SingleRequest实现的ResourceCallback接口。
资源通知SingleRequest内部Target。
任重而道远