在Glide源码分析(三),Engine加载资源过程文中,我们分析到Engine#load的最后一步,创建好了一对EngineJob和DecodeJob,随之调用EngineJob的start方法,启动加载任务。下面分析整个一个执行过程,文中相关情景下的方法特定调用的结果是还是基于一下这段code,虽然是由特殊入口,并不影响我们理解整个框架,反而是一个很好的突破口,理解代码的思想。示例代码如下:
Glide.with(this)
.load("https://p.upyun.com/docs/cloud/demo.jpg")
.into(imageView);
此时的情景就是加载一个普通的http url对象。下面我们开始分析,加载的起点,也就是从EngineJob#start开始。
1. EngineJob#start
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
这个方法是根据当前条件,选取一个GlideExecutor,它实现了ExecutorService,然后由它去执行decodeJob。通过decodeJob的willDecodeFromCache方法,决定是使用哪一个。Glide里面,封装了很几种类型的线程池对象,这里无需深究哪个线程池这个细节。显然DecodeJob是一个Runnable对象,最终执行之后,都是触发DecodeJob的run方法。
2.DecodeJob#run
@Override
public void run() {
// This should be much more fine grained, but since Java's thread pool implementation silently
// swallows all otherwise fatal exceptions, this will at least make it obvious to developers
// that something is failing.
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
// Methods in the try statement can invalidate currentFetcher, so set a local variable here to
// ensure that the fetcher is cleaned up either way.
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (Throwable t) {
// Catch Throwable and not Exception to handle OOMs. Throwables are swallowed by our
// usage of .submit() in GlideExecutor so we're not silently hiding crashes by doing this. We
// are however ensuring that our callbacks are always notified when a load fails. Without this
// notification, uncaught throwables never notify the corresponding callbacks, which can cause
// loads to silently hang forever, a case that's especially bad for users using Futures on
// background threads.
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "DecodeJob threw unexpectedly"
+ ", isCancelled: " + isCancelled
+ ", stage: " + stage, t);
}
// When we're encoding we've already notified our callback and it isn't safe to do so again.
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
} finally {
// Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call
// close in all cases anyway.
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
执行run方法时候,首先检查isCancelled标志位,它是一个volatile变量,保证了多线程之间的可见性,由此可知道DecodeJob是支持取消的。如果此时,已经被取消,则会调用notifyFailed方法,它里面主要是通过callback回调告知上层调用者,这里就是EngineJob,其二是清理和重置DecodeJob里面的一些资源。另外如果未被取消,如果有任何异常出现,则会进入catch方法块,也会看条件进行一些回调和清理资源,同时在finally代码块中,执行已经结束,localFetcher记录着当前的currentFetcher对象,这个时候会通知DataFetcher的cleanup清理资源,因为DecodeJob是可被复用的,显然第一次运行localFetcher是null,后面我们分析到了这个再具体看看它的用处。下面我们分析重点方法,runWapped这个的执行逻辑。
3. DecodeJon#runWapped
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE: