在第一部分with()和 load()方法已经分析完了,在第二部分我们将继续into()方法分析。
- into()
如果说前面两步都是在准备开胃小菜的话,那么现在终于要进入主菜了,因为 into() 方法也是整个 Glide 图片加载流程中逻辑最复杂的地方。
不过从刚才的代码来看,into() 方法中并没有任何逻辑,只有一句 super.into(view)。那么很显然,into() 方法的具体逻辑都是在 DrawableRequestBuilder 的父类当中了。
DrawableRequestBuilder 的父类是 GenericRequestBuilder,我们来看一下 GenericRequestBuilder 类中的 into() 方法,如下所示:
public Target<TranscodeType> into(ImageView view) {
Util.assertMainThread();
if (view == null) {
throw new IllegalArgumentException("You must pass in a non null View");
}
if (!isTransformationSet && view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
applyCenterCrop();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
applyFitCenter();
break;
default:
}
}
return into(glide.buildImageViewTarget(view, transcodeClass));
}
这里前面一大堆的判断逻辑我们都可以先不用管,等到后面文章讲 transform 的时候会再进行解释,现在我们只需要关注最后一行代码。最后一行代码先是调用了 glide.buildImageViewTarget() 方法,这个方法会构建出一个 Target 对象,Target 对象则是用来最终展示图片用的,如果我们跟进去的话会看到如下代码:
<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
}
这里其实又是调用了 ImageViewTargetFactory 的 buildTarget() 方法,我们继续跟进去,代码如下所示:
public class ImageViewTargetFactory {
@SuppressWarnings("unchecked")
public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
if (GlideDrawable.class.isAssignableFrom(clazz)) {
return (Target<Z>) new GlideDrawableImageViewTarget(view);
} else if (Bitmap.class.equals(clazz)) {
return (Target<Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (Target<Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException("Unhandled class: " + clazz
+ ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
}
可以看到,在 buildTarget() 方法中会根据传入的 class 参数来构建不同的 Target 对象。那如果你要分析这个 class 参数是从哪儿传过来的,这可有得你分析了,简单起见我直接帮大家梳理清楚。这个 class 参数其实基本上只有两种情况,如果你在使用 Glide 加载图片的时候调用了 asBitmap() 方法,那么这里就会构建出 BitmapImageViewTarget 对象,否则的话构建的都是 GlideDrawableImageViewTarget 对象。至于上述代码中的 DrawableImageViewTarget 对象,这个通常都是用不到的,我们可以暂时不用管它。
也就是说,通过 glide.buildImageViewTarget() 方法,我们构建出了一个 GlideDrawableImageViewTarget 对象。那现在回到刚才 into() 方法的最后一行,可以看到,这里又将这个参数传入到了 GenericRequestBuilder 另一个接收 Target 对象的 into() 方法当中了。我们来看一下这个 into() 方法的源码:
public <Y extends Target<TranscodeType>> Y into(Y target) {
Util.assertMainThread();
if (target == null) {
throw new IllegalArgumentException("You must pass in a non null Target");
}
if (!isModelSet) {
throw new IllegalArgumentException("You must first set a model (try #load())");
}
Request previous = target.getRequest();
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
Request request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
requestTracker.runRequest(request);
return target;
}
这里我们还是只抓核心代码,其实只有两行是最关键的,第 15 行调用 buildRequest() 方法构建出了一个 Request 对象,还有第 18 行来执行这个 Request。
Request 是用来发出加载图片请求的,它是 Glide 中非常关键的一个组件。我们先来看 buildRequest() 方法是如何构建 Request 对象的:
private Request buildRequest(Target<TranscodeType> target) {
if (priority == null) {
priority = Priority.NORMAL;
}
return buildRequestRecursive(target, null);
}
private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
if (thumbnailRequestBuilder != null) {
if (isThumbnailBuilt) {
throw new IllegalStateException("You cannot use a request as both the main request and a thumbnail, "
+ "consider using clone() on the request(s) passed to thumbnail()");
}
if (thumbnailRequestBuilder.animationFactory.equals(NoAnimation.getFactory())) {
thumbnailRequestBuilder.animationFactory = animationFactory;
}
if (thumbnailRequestBuilder.priority == null) {
thumbnailRequestBuilder.priority = getThumbnailPriority();
}
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !Util.isValidDimensions(thumbnailRequestBuilder.overrideWidth,
thumbnailRequestBuilder.overrideHeight)) {
thumbnailRequestBuilder.override(overrideWidth, overrideHeight);
}
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
isThumbnailBuilt = true;
Request thumbRequest = thumbnailRequestBuilder.buildRequestRecursive(target, coordinator);
isThumbnailBuilt = false;
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
} else if (thumbSizeMultiplier != null) {
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
Request thumbnailRequest = obtainRequest(target, thumbSizeMultiplier, getThumbnailPriority(), coordinator);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
}
private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
RequestCoordinator requestCoordinator) {
return GenericRequest.obtain(
loadProvider,
model,
signature,
context,
priority,
target,
sizeMultiplier,
placeholderDrawable,
placeholderId,
errorPlaceholder,
errorId,
fallbackDrawable,
fallbackResource,
requestListener,
requestCoordinator,
glide.getEngine(),
transformation,
transcodeClass,
isCacheable,
animationFactory,
overrideWidth,
overrideHeight,
diskCacheStrategy);
}
可以看到,buildRequest() 方法的内部其实又调用了 buildRequestRecursive() 方法,而 buildRequestRecursive() 方法中的代码虽然有点长,但是其中 90% 的代码都是在处理缩略图的。如果我们只追主线流程的话,那么只需要看第 47 行代码就可以了。这里调用了 obtainRequest() 方法来获取一个 Request 对象,而 obtainRequest() 方法中又去调用了 GenericRequest 的 obtain() 方法。注意这个 obtain() 方法需要传入非常多的参数,而其中很多的参数我们都是比较熟悉的,像什么 placeholderId、errorPlaceholder、diskCacheStrategy 等等。因此,我们就有理由猜测,刚才在 load() 方法中调用的所有 API,其实都是在这里组装到 Request 对象当中的。那么我们进入到这个 GenericRequest 的 obtain() 方法瞧一瞧:
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,
ResourceCallback {
...
public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(
LoadProvider<A, T, Z, R> loadProvider,
A model,
Key signature,
Context context,
Priority priority,
Target<R> target,
float sizeMultiplier,
Drawable placeholderDrawable,
int placeholderResourceId,
Drawable errorDrawable,
int errorResourceId,
Drawable fallbackDrawable,
int fallbackResourceId,
RequestListener<? super A, R> requestListener,
RequestCoordinator requestCoordinator,
Engine engine,
Transformation<Z> transformation,
Class<R> transcodeClass,
boolean isMemoryCacheable,
GlideAnimationFactory<R> animationFactory,
int overrideWidth,
int overrideHeight,
DiskCacheStrategy diskCacheStrategy) {
@SuppressWarnings("unchecked")
GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
if (request == null) {
request = new GenericRequest<A, T, Z, R>();
}
request.init(loadProvider,
model,
signature,
context,
priority,
target,
sizeMultiplier,
placeholderDrawable,
placeholderResourceId,
errorDrawable,
errorResourceId,
fallbackDrawable,
fallbackResourceId,
requestListener,
requestCoordinator,
engine,
transformation,
transcodeClass,
isMemoryCacheable,
animationFactory,
overrideWidth,
overrideHeight,
diskCacheStrategy);
return request;
}
...
}
可以看到,这里在第 33 行去 new 了一个 GenericRequest 对象,并在最后一行返回,也就是说,obtain() 方法实际上获得的就是一个 GenericRequest 对象。另外这里又在第 35 行调用了 GenericRequest 的 init(),里面主要就是一些赋值的代码,将传入的这些参数赋值到 GenericRequest 的成员变量当中,我们就不再跟进去看了。
好,那现在解决了构建 Request 对象的问题,接下来我们看一下这个 Request 对象又是怎么执行的。回到刚才的 into() 方法,你会发现在第 18 行调用了 requestTracker.runRequest() 方法来去执行这个 Request,那么我们跟进去瞧一瞧,如下所示:
/**
* Starts tracking the given request.
*/
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
这里有一个简单的逻辑判断,就是先判断 Glide 当前是不是处理暂停状态,如果不是暂停状态就调用 Request 的 begin() 方法来执行 Request,否则的话就先将 Request 添加到待执行队列里面,等暂停状态解除了之后再执行。
暂停请求的功能仍然不是这篇文章所关心的,这里就直接忽略了,我们重点来看这个 begin() 方法。由于当前的 Request 对象是一个 GenericRequest,因此这里就需要看 GenericRequest 中的 begin() 方法了,如下所示:
@Override
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
这里我们来注意几个细节,首先如果 model 等于 null,model 也就是我们在第二步 load() 方法中传入的图片 URL 地址,这个时候会调用 onException() 方法。如果你跟到 onException() 方法里面去看看,你会发现它最终会调用到一个 setErrorPlaceholder() 当中,如下所示:
private void setErrorPlaceholder(Exception e) {
if (!canNotifyStatusChanged()) {
return;
}
Drawable error = model == null ? getFallbackDrawable() : null;
if (error == null) {
error = getErrorDrawable();
}
if (error == null) {
error = getPlaceholderDrawable();
}
target.onLoadFailed(e, error);
}
这个方法中会先去获取一个 error 的占位图,如果获取不到的话会再去获取一个 loading 占位图,然后调用 target.onLoadFailed() 方法并将占位图传入。那么 onLoadFailed() 方法中做了什么呢?我们看一下:
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements GlideAnimation.ViewAdapter {
...
@Override
public void onLoadStarted(Drawable placeholder) {
view.setImageDrawable(placeholder);
}
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
view.setImageDrawable(errorDrawable);
}
...
}
很简单,其实就是将这张 error 占位图显示到 ImageView 上而已,因为现在出现了异常,没办法展示正常的图片了。而如果你仔细看下刚才 begin() 方法的第 15 行,你会发现它又调用了一个 target.onLoadStarted() 方法,并传入了一个 loading 占位图,在也就说,在图片请求开始之前,会先使用这张占位图代替最终的图片显示。这也是我们在上一篇文章中学过的 placeholder() 和 error() 这两个占位图 API 底层的实现原理。
好,那么我们继续回到 begin() 方法。刚才讲了占位图的实现,那么具体的图片加载又是从哪里开始的呢?是在 begin() 方法的第 10 行和第 12 行。这里要分两种情况,一种是你使用了 override() API 为图片指定了一个固定的宽高,一种是没有指定。如果指定了的话,就会执行第 10 行代码,调用 onSizeReady() 方法。如果没指定的话,就会执行第 12 行代码,调用 target.getSize() 方法。这个 target.getSize() 方法的内部会根据 ImageView 的 layout_width 和 layout_height 值做一系列的计算,来算出图片应该的宽高。具体的计算细节我就不带着大家分析了,总之在计算完之后,它也会调用 onSizeReady() 方法。也就是说,不管是哪种情况,最终都会调用到 onSizeReady() 方法,在这里进行下一步操作。那么我们跟到这个方法里面来:
@Override
public void onSizeReady(int width, int height) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
width = Math.round(sizeMultiplier * width);
height = Math.round(sizeMultiplier * height);
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadedFromMemoryCache = true;
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
loadedFromMemoryCache = resource != null;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
从这里开始,真正复杂的地方来了,我们需要慢慢进行分析。先来看一下,在第 12 行调用了 loadProvider.getModelLoader() 方法,那么我们第一个要搞清楚的就是,这个 loadProvider 是什么?要搞清楚这点,需要先回到第二步的 load() 方法当中。还记得 load() 方法是返回一个 DrawableTypeRequest 对象吗?刚才我们只是分析了 DrawableTypeRequest 当中的 asBitmap() 和 asGif() 方法,并没有仔细看它的构造函数,现在我们重新来看一下 DrawableTypeRequest 类的构造函数:
public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
private final ModelLoader<ModelType, InputStream> streamModelLoader;
private final ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader;
private final RequestManager.OptionsApplier optionsApplier;
private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
ModelLoader<A, InputStream> streamModelLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
Class<R> transcodedClass,
ResourceTranscoder<Z, R> transcoder) {
if (streamModelLoader == null && fileDescriptorModelLoader == null) {
return null;
}
if (transcoder == null) {
transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
}
DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
resourceClass);
ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
fileDescriptorModelLoader);
return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
}
DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) {
super(context, modelClass,
buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
GlideDrawable.class, null),
glide, requestTracker, lifecycle);
this.streamModelLoader = streamModelLoader;
this.fileDescriptorModelLoader = fileDescriptorModelLoader;
this.optionsApplier = optionsApplier;
}
...
}
可以看到,这里在第 29 行,也就是构造函数中,调用了一个 buildProvider() 方法,并把 streamModelLoader 和 fileDescriptorModelLoader 等参数传入到这个方法中,这两个 ModelLoader 就是之前在 loadGeneric() 方法中构建出来的。
那么我们再来看一下 buildProvider() 方法里面做了什么,在第 16 行调用了 glide.buildTranscoder() 方法来构建一个 ResourceTranscoder,它是用于对图片进行转码的,由于 ResourceTranscoder 是一个接口,这里实际会构建出一个 GifBitmapWrapperDrawableTranscoder 对象。
接下来在第 18 行调用了 glide.buildDataProvider() 方法来构建一个 DataLoadProvider,它是用于对图片进行编解码的,由于 DataLoadProvider 是一个接口,这里实际会构建出一个 ImageVideoGifDrawableLoadProvider 对象。
然后在第 20 行,new 了一个 ImageVideoModelLoader 的实例,并把之前 loadGeneric() 方法中构建的两个 ModelLoader 封装到了 ImageVideoModelLoader 当中。
最后,在第 22 行,new 出一个 FixedLoadProvider,并把刚才构建的出来的 GifBitmapWrapperDrawableTranscoder、ImageVideoModelLoader、ImageVideoGifDrawableLoadProvider 都封装进去,这个也就是 onSizeReady() 方法中的 loadProvider 了。
好的,那么我们回到 onSizeReady() 方法中,在 onSizeReady() 方法的第 12 行和第 18 行,分别调用了 loadProvider 的 getModelLoader() 方法和 getTranscoder() 方法,那么得到的对象也就是刚才我们分析的 ImageVideoModelLoader 和 GifBitmapWrapperDrawableTranscoder 了。而在第 13 行,又调用了 ImageVideoModelLoader 的 getResourceFetcher() 方法,这里我们又需要跟进去瞧一瞧了,代码如下所示:
public class ImageVideoModelLoader<A> implements ModelLoader<A, ImageVideoWrapper> {
private static final String TAG = "IVML";
private final ModelLoader<A, InputStream> streamLoader;
private final ModelLoader<A, ParcelFileDescriptor> fileDescriptorLoader;
public ImageVideoModelLoader(ModelLoader<A, InputStream> streamLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorLoader) {
if (streamLoader == null && fileDescriptorLoader == null) {
throw new NullPointerException("At least one of streamLoader and fileDescriptorLoader must be non null");
}
this.streamLoader = streamLoader;
this.fileDescriptorLoader = fileDescriptorLoader;
}
@Override
public DataFetcher<ImageVideoWrapper> getResourceFetcher(A model, int width, int height) {
DataFetcher<InputStream> streamFetcher = null;
if (streamLoader != null) {
streamFetcher = streamLoader.getResourceFetcher(model, width, height);
}
DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher = null;
if (fileDescriptorLoader != null) {
fileDescriptorFetcher = fileDescriptorLoader.getResourceFetcher(model, width, height);
}
if (streamFetcher != null || fileDescriptorFetcher != null) {
return new ImageVideoFetcher(streamFetcher, fileDescriptorFetcher);
} else {
return null;
}
}
static class ImageVideoFetcher implements DataFetcher<ImageVideoWrapper> {
private final DataFetcher<InputStream> streamFetcher;
private final DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher;
public ImageVideoFetcher(DataFetcher<InputStream> streamFetcher,
DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher) {
this.streamFetcher = streamFetcher;
this.fileDescriptorFetcher = fileDescriptorFetcher;
}
...
}
}
可以看到,在第 20 行会先调用 streamLoader.getResourceFetcher() 方法获取一个 DataFetcher,而这个 streamLoader 其实就是我们在 loadGeneric() 方法中构建出的 StreamStringLoader,调用它的 getResourceFetcher() 方法会得到一个 HttpUrlFetcher 对象。然后在第 28 行 new 出了一个 ImageVideoFetcher 对象,并把获得的 HttpUrlFetcher 对象传进去。也就是说,ImageVideoModelLoader 的 getResourceFetcher() 方法得到的是一个 ImageVideoFetcher。
那么我们再次回到 onSizeReady() 方法,在 onSizeReady() 方法的第 23 行,这里将刚才获得的 ImageVideoFetcher、GifBitmapWrapperDrawableTranscoder 等等一系列的值一起传入到了 Engine 的 load() 方法当中。接下来我们就要看一看,这个 Engine 的 load() 方法当中,到底做了什么?代码如下所示:
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
...
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
Util.assertMainThread();
long startTime = LogTime.getLogTime();
final String id = fetcher.getId();
EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
transcoder, loadProvider.getSourceEncoder());
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
EngineJob current = jobs.get(key);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
...
}
load() 方法中的代码虽然有点长,但大多数的代码都是在处理缓存的。关于缓存的内容我们会在下一篇文章当中学习,现在只需要从第 45 行看起就行。这里构建了一个 EngineJob,它的主要作用就是用来开启线程的,为后面的异步加载图片做准备。接下来第 46 行创建了一个 DecodeJob 对象,从名字上来看,它好像是用来对图片进行解码的,但实际上它的任务十分繁重,待会我们就知道了。继续往下看,第 48 行创建了一个 EngineRunnable 对象,并且在 51 行调用了 EngineJob 的 start() 方法来运行 EngineRunnable 对象,这实际上就是让 EngineRunnable 的 run() 方法在子线程当中执行了。那么我们现在就可以去看看 EngineRunnable 的 run() 方法里做了些什么,如下所示:
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource<?> resource = null;
try {
resource = decode();
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception decoding", e);
}
exception = e;
}
if (isCancelled) {
if (resource != null) {
resource.recycle();
}
return;
}
if (resource == null) {
onLoadFailed(exception);
} else {
onLoadComplete(resource);
}
}
这个方法中的代码并不多,但我们仍然还是要抓重点。在第 9 行,这里调用了一个 decode() 方法,并且这个方法返回了一个 Resource 对象。看上去所有的逻辑应该都在这个 decode() 方法执行的了,那我们跟进去瞧一瞧:
private Resource<?> decode() throws Exception {
if (isDecodingFromCache()) {
return decodeFromCache();
} else {
return decodeFromSource();
}
}
decode() 方法中又分了两种情况,从缓存当中去 decode 图片的话就会执行 decodeFromCache(),否则的话就执行 decodeFromSource()。本篇文章中我们不讨论缓存的情况,那么就直接来看 decodeFromSource() 方法的代码吧,如下所示:
private Resource<?> decodeFromSource() throws Exception {
return decodeJob.decodeFromSource();
}
这里又调用了 DecodeJob 的 decodeFromSource() 方法。刚才已经说了,DecodeJob 的任务十分繁重,我们继续跟进看一看吧:
class DecodeJob<A, T, Z> {
...
public Resource<Z> decodeFromSource() throws Exception {
Resource<T> decoded = decodeSource();
return transformEncodeAndTranscode(decoded);
}
private Resource<T> decodeSource() throws Exception {
Resource<T> decoded = null;
try {
long startTime = LogTime.getLogTime();
final A data = fetcher.loadData(priority);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Fetched data", startTime);
}
if (isCancelled) {
return null;
}
decoded = decodeFromSourceData(data);
} finally {
fetcher.cleanup();
}
return decoded;
}
...
}
主要的方法就这些,我都帮大家提取出来了。那么我们先来看一下 decodeFromSource() 方法,其实它的工作分为两部,第一步是调用 decodeSource() 方法来获得一个 Resource 对象,第二步是调用 transformEncodeAndTranscode() 方法来处理这个 Resource 对象。
由于篇幅有限,在这篇文章的最后一部分的分析在下一篇文章中会介绍给大家,欢迎大家参与讨论。