Glide源码(4.11.0)主线流程梳理(二)---load&into方法的内部逻辑
load 源码梳理
根据上篇文章对with方法的梳理可以知道,Glide.with(this) 返回的是RequestManager对象,所以load方法在RequestManager类里面,现在我们分析一下load方法
public class RequestManager implements ComponentCallbacks2, LifecycleListener, ModelTypes<RequestBuilder<Drawable>> { @NonNull @CheckResult public RequestBuilder<Drawable> asDrawable() { return as(Drawable.class); } @NonNull @CheckResult @Override public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) { return asDrawable().load(bitmap); } @NonNull @CheckResult @Override public RequestBuilder<Drawable> load(@Nullable Drawable drawable) { return asDrawable().load(drawable); } @NonNull @CheckResult @Override public RequestBuilder<Drawable> load(@Nullable String string) { return asDrawable().load(string); }// ... @NonNull @CheckResult public <ResourceType> RequestBuilder<ResourceType> as(@NonNull Class<ResourceType> resourceClass) { return new RequestBuilder<>(glide, this, resourceClass, context); } }
从上面的代码可见,asDrawable()方法的主要作用就是构建RequestBuilder;
代码拆开来看,
// 伪代码public RequestBuilder<Drawable> load(@Nullable String string) { RequestBuilder requestBuilder = asDrawable();requestBuilder = requestBuilder.load(string); return requestBuilder; }
下面进入RequestBuilder类,看一下RequestBuilder.load(string)方法;
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>> implements Cloneable, ModelTypes<RequestBuilder<TranscodeType>> { public RequestBuilder<TranscodeType> load(@RawRes @DrawableRes @Nullable Integer resourceId) { return loadGeneric(resourceId).apply(signatureOf(AndroidResourceSignature.obtain(context))); } @NonNull private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) { this.model = model;// 相当于传递过来的资源url isModelSet = true;// 标记已经加载过资源 return this;// 返回RequestBuilder }//这个主要是调用父类的方法,初始化 配置信息 @Override public RequestBuilder<TranscodeType> apply(@NonNull BaseRequestOptions<?> requestOptions) { Preconditions.checkNotNull(requestOptions); return super.apply(requestOptions); }}
至此,load方法的主线流程就差不多完事了,主要就是构建RequestBuilder,为了下一步into做准备
into() 源码梳理
这里才算是真正进入Glide源码的核心之处
由于load方法返回的是RequestBuilder,所以 into方法肯定是在RequestBuilder类里面
RequestBuilder.java
@NonNull public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) { Util.assertMainThread();// 主线程检查 Preconditions.checkNotNull(view);// 目标控件 空检查//根据布局文件里面scaleType属性的设置,重置RequestOptions BaseRequestOptions<?> requestOptions = this; if (!requestOptions.isTransformationSet() && requestOptions.isTransformationAllowed() && view.getScaleType() != null) { // Clone in this method so that if we use this RequestBuilder to load into a View and then // into a different target, we don't retain the transformation applied based on the previous // View's scale type. switch (view.getScaleType()) { case CENTER_CROP: requestOptions = requestOptions.clone().optionalCenterCrop(); break; case CENTER_INSIDE: requestOptions = requestOptions.clone().optionalCenterInside(); break; case FIT_CENTER: case FIT_START: case FIT_END: requestOptions = requestOptions.clone().optionalFitCenter(); break; case FIT_XY: requestOptions = requestOptions.clone().optionalCenterInside(); break; case CENTER: case MATRIX: default: // Do nothing. } }//调用 into 重载函数,创建一个 ViewTarget return into( //调用 buildImageViewTarget 构建一个 ImageView 类型的 Target(Bitmap/Drawable) glideContext.buildImageViewTarget(view, transcodeClass), /*targetListener=*/ null, requestOptions, Executors.mainThreadExecutor()); }
上面代码就两大步:
第一步:先拿到当前 ImageView getScaleType 类型的属性,然后重新 clone 一个进行配置;
第二步:调用 into 重载继续构建;
- 先来看下into方法的第一个参数 glideContext.buildImageViewTarget 是怎么构建出来 ImageViewTarget 的:
@NonNull public <X> ViewTarget<ImageView, X> buildImageViewTarget( @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) { return imageViewTargetFactory.buildTarget(imageView, transcodeClass); }
public class ImageViewTargetFactory { @NonNull @SuppressWarnings("unchecked") public <Z> ViewTarget<ImageView, Z> buildTarget( @NonNull ImageView view, @NonNull Class<Z> clazz) { if (Bitmap.class.equals(clazz)) { //如果目标的编码类型属于 Bitmap 那么就创建一个 Bitmap 类型的 ImageViewTarget return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view); } else if (Drawable.class.isAssignableFrom(clazz)) { //如果目标的编码类型属于 Drawable 那么就创建一个 Drawable 类型的 ImageViewTarget return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view); } else { throw new IllegalArgumentException( "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)"); } }}
注意:上面 生成Target 的时候注意一下,只要调用了 asBitmap
才会执行生成BitmapImageViewTarget ,所以这里我们关注 Drawable 类型就行了,我们就先简单看看这个 target 内部怎么实现的
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> { public DrawableImageViewTarget(ImageView view) { super(view); } /** @deprecated Use {@link #waitForLayout()} instead. */ // Public API. @SuppressWarnings({"unused", "deprecation"}) @Deprecated public DrawableImageViewTarget(ImageView view, boolean waitForLayout) { super(view, waitForLayout); } @Override protected void setResource(@Nullable Drawable resource) { view.setImageDrawable(resource); }}
这里DrawableImageViewTarget 继承 ImageViewTarget,重写了setResource方法,这里是显示图片到控件上的逻辑,记住这里
- 继续重载into方法
private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options, Executor callbackExecutor) { Preconditions.checkNotNull(target); //这里的 isModelSet 是在 load 的时候赋值为 true 的,所以不会抛异常 if (!isModelSet) { throw new IllegalArgumentException("You must call #load() before calling #into()"); }//为这个 http://xxx.png 生成一个 Glide request 请求 Request request = buildRequest(target, targetListener, options, callbackExecutor);//相当于拿到上一个请求 Request previous = target.getRequest();// 先取Request, //下面的几行说明是否与上一个请求冲突,一般不用管 直接看下面 else 判断 if (request.isEquivalentTo(previous) && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { // 意思就是说 如果当前请求跟上一次的请求是同一个,那就释放本次请求,执行上一个请求, request.recycle(); if (!Preconditions.checkNotNull(previous).isRunning()) { previous.begin(); } return target; }//清理掉目标请求管理 requestManager.clear(target); //重新为目标设置一个 Glide request 请求 target.setRequest(request); //最后是调用 RequestManager 的 track 来执行目标的 Glide request 请求 requestManager.track(target, request); return target; }
以上核心就两个点:
- 第一点:为 target buildRequest 构建一个 Glide request 请求;
- 第二点:将构建出来的 Request 交于 RequestManager 来执行
简单的来看下怎么构建的 Request:
private Request buildRequest(...) { return buildRequestRecursive(...省略参数); } // .... 一系列的方法调用,最终执行到下面的方法 private Request obtainRequest(...省略参数) { return SingleRequest.obtain(...省略参数); }
最终是调用了SingleRequest.obtain方法,得到Request之后,交给RequestManager执行requestManager.track(target, request);
synchronized void track(@NonNull Target<?> target, @NonNull Request request) { //添加一个目标任务 targetTracker.track(target); //执行 Glide request requestTracker.runRequest(request); }
public void runRequest(@NonNull Request request) { //添加一个请求 requests.add(request); //是否暂停 if (!isPaused) { //没有暂停,开始调用 Request begin 执行 request.begin(); } else { //如果调用了 暂停,清理请求 request.clear(); pendingRequests.add(request); } }
继续查看Request的执行begin()方法,
前面已经备注得到的Request是 SingleRequest,所以,在点击begin方法的时候进入了接口Request里面的begin方法,这时候去找实现类,就应该找 SingleRequest的begin方法;
SingleRequest.java
@Override public void begin() { synchronized (requestLock) { assertNotCallingCallbacks(); stateVerifier.throwIfRecycled(); startTime = LogTime.getLogTime(); if (model == null) { //检查外部调用的尺寸是否有效 if (Util.isValidDimensions(overrideWidth, overrideHeight)) { width = overrideWidth; height = overrideHeight; } //失败的回调 int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG; onLoadFailed(new GlideException("Received null model"), logLevel); return; } if (status == Status.RUNNING) { throw new IllegalArgumentException("Cannot restart a running request"); } if (status == Status.COMPLETE) {//表示资源准备好了 onResourceReady(resource, DataSource.MEMORY_CACHE); return; } status = Status.WAITING_FOR_SIZE; if (Util.isValidDimensions(overrideWidth, overrideHeight)) { //这里表示大小已经准备好了---去寻找缓存,准备资源 onSizeReady(overrideWidth, overrideHeight); } else { target.getSize(this); } if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE) && canNotifyStatusChanged()) { target.onLoadStarted(getPlaceholderDrawable()); } if (IS_VERBOSE_LOGGABLE) { logV("finished run method in " + LogTime.getElapsedMillis(startTime)); } } }
大小准备好之后 去寻找缓存,准备资源
onSizeReady
@Override public void onSizeReady(int width, int height) { stateVerifier.throwIfRecycled(); synchronized (requestLock) { // ... loadStatus = engine.load(...省略参数);// ... } }
Engine.java
engine.load
public <R> LoadStatus load(...) {// 拿到 key EngineKey key = keyFactory.buildKey(...); EngineResource<?> memoryResource; synchronized (this) { // 去内存查找 memoryResource = loadFromMemory(key, isMemoryCacheable, startTime); if (memoryResource == null) {//内存没有找到,执行一个新的任务 return waitForExistingOrStartNewJob(...); } } cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE); return null; } // 执行已经存在的任务 或者 开启一个新任务 private <R> LoadStatus waitForExistingOrStartNewJob(...) { EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache); if (current != null) { current.addCallback(cb, callbackExecutor); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Added to existing load", startTime, key); } return new LoadStatus(cb, current); } EngineJob<R> engineJob = engineJobFactory.build(...); DecodeJob<R> decodeJob = decodeJobFactory.build(...); //把当前需要执行的 key 添加进缓存 jobs.put(key, engineJob);//执行任务的回调 engineJob.addCallback(cb, callbackExecutor); //开始执行。 engineJob.start(decodeJob); // ... return new LoadStatus(cb, engineJob); }
查找内存的过程
@Nullable private EngineResource<?> loadFromMemory( EngineKey key, boolean isMemoryCacheable, long startTime) { if (!isMemoryCacheable) { return null; }// 查找活动缓存 EngineResource<?> active = loadFromActiveResources(key); if (active != null) { // 活动缓存有,就返回 return active; }// 活动缓存没找到,查找内存缓存 EngineResource<?> cached = loadFromCache(key); if (cached != null) { // 内存缓存有,就返回 return cached; } // 活动缓存、内存缓存都没有,就返回null return null; } // 查找内存缓存 private EngineResource<?> loadFromCache(Key key) { EngineResource<?> cached = getEngineResourceFromCache(key); if (cached != null) { cached.acquire(); // 如果内存缓存找到了,就放到活动缓存里面去 //此处注意,是剪切,意思就是 内存缓存和活动缓存只能有一处,不能共存, // 详情请继续查看activate方法 activeResources.activate(key, cached); } return cached; }
通过 engine.load
这个函数里面的逻辑,同学们我们可以总结3点:
-
先构建请求或者缓存 KEY ;
-
根据 KEY 从内存缓存中查找对应的资源数据(ActiveResources(活动缓存,内部是一个 Map 用弱引用持有),LruResourceCache),如果有就回调 对应监听的 onResourceReady 表示数据准备好了。
-
从执行缓存中查找对应 key 的任务
-
如果找到了,就说明已经正在执行了,不用重复执行。
-
没有找到,通过 EngineJob.start 开启一个新的请求任务执行。
-
下面我们就来看下 engineJob.start
具体执行逻辑:
engineJob.start(decodeJob);
public synchronized void start(DecodeJob<R> decodeJob) { this.decodeJob = decodeJob; // 从线程池里得到线程 GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor(); //开始执行 executor.execute(decodeJob); }
通过 DecodeJob
源码得知,它是实现的 Runnable
接口,这里 GlideExecutor 线程池开始执行,就会启动 DecodeJob 的 run 函数,我们跟踪 run 的实现:
class DecodeJob<R> implements Runnable ...{ @Override public void run() { // ... if (isCancelled) { notifyFailed(); return; } // 开始执行 runWrapped(); // ... }}
private void runWrapped() { switch (runReason) { case INITIALIZE: //获取资源状态 stage = getNextStage(Stage.INITIALIZE); //根据当前资源状态,获取资源执行器 currentGenerator = getNextGenerator(); //执行 runGenerators(); break; ... } } private Stage getNextStage(Stage current) { switch (current) { case INITIALIZE: //如果外部调用配置了资源缓存策略,那么返回 Stage.RESOURCE_CACHE//否则继续调用 Stage.RESOURCE_CACHE 执行。 return diskCacheStrategy.decodeCachedResource() ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE); case RESOURCE_CACHE: //如果外部配置了源数据缓存,那么返回 Stage.DATA_CACHE //否则继续调用 getNextStage(Stage.DATA_CACHE) return diskCacheStrategy.decodeCachedData() ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE); case DATA_CACHE: //如果只能从缓存中获取数据,则直接返回 FINISHED,否则,返回SOURCE。 //意思就是一个新的资源 return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE; case SOURCE: case FINISHED: return Stage.FINISHED; default: throw new IllegalArgumentException("Unrecognized stage: " + current); } }
通过上面代码可以知道,我们在找资源的执行器,这里由于我们没有在外部配置缓存策略所以,直接从源数据加载,看下面代码:
private DataFetcherGenerator getNextGenerator() { switch (stage) { //从资源缓存执行器 case RESOURCE_CACHE: return new ResourceCacheGenerator(decodeHelper, this); //源数据磁盘缓存执行器 case DATA_CACHE: return new DataCacheGenerator(decodeHelper, this); //什么都没有配置,源数据的执行器 case SOURCE: return new SourceGenerator(decodeHelper, this); case FINISHED: return null; default: throw new IllegalStateException("Unrecognized stage: " + stage); } }
由于我们什么都没有配置,返回的是 SourceGenerator
源数据执行器。继续下面代码执行:
runGenerators()
private void runGenerators() { // ... while (!isCancelled && currentGenerator != null && !(isStarted = currentGenerator.startNext())) { stage = getNextStage(stage); currentGenerator = getNextGenerator(); // ... }
着重看 while循环里面的currentGenerator.startNext();
DataFetcherGenerator
是一个抽象类,那么这里执行的实现类是哪一个,可以参考下面说明:
Stage.RESOURCE_CACHE【状态标记】 ---- 从磁盘中获取缓存的资源数据【作用】 — ResourceCacheGenerator【执行器】
Stage.DATA_CACHE【状态标记】 ---- 从磁盘中获取缓存的源数据【作用】 — DataCacheGenerator【执行器】
Stage.SOURCE【状态标记】 — 一次新的请求任务 — SourceGenerator【执行器】
因为这里我们没有配置缓存,那么直接看 SourceGenerator
@Override public boolean startNext() {... loadData = null; boolean started = false; while (!started && hasNextModelLoader()) { //获取一个 ModelLoad 加载器 loadData = helper.getLoadData().get(loadDataListIndex++); if (loadData != null && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource()) || helper.hasLoadPath(loadData.fetcher.getDataClass()))) { started = true; //使用加载器中的 fetcher 根据优先级加载数据 loadData.fetcher.loadData(helper.getPriority(), new DataCallback<Object>() { @Override public void onDataReady(@Nullable Object data) { if (isCurrentRequest(toStart)) { //这里需要记住,后面资源准备好之后 ,会回调到这里onDataReadyInternal(toStart, data); } } @Override public void onLoadFailed(@NonNull Exception e) { if (isCurrentRequest(toStart)) {onLoadFailedInternal(toStart, e); } } }); } } return started; }
helper.getLoadData()
获取的是一个什么样的加载器,我们可以先猜一下,因为没有配置任何缓存,所以可以猜得到是 http 请求了,那么是不是猜测的那样的,我们一起来验证下。
List<LoadData<?>> getLoadData() { if (!isLoadDataSet) { isLoadDataSet = true; loadData.clear();//从 Glide 注册的 Model 来获取加载器(注册是在 Glide 初始化的时候通过 registry// .append()添加的) List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model); for (int i = 0, size = modelLoaders.size(); i < size; i++) { ModelLoader<Object, ?> modelLoader = modelLoaders.get(i); LoadData<?> current = //开始构建加载器 modelLoader.buildLoadData(model, width, height, options); //如果架子啊器不为空,那么添加进临时缓存 if (current != null) { loadData.add(current); } } } return loadData; }
首先拿到一个加载器的容器,加载器是在 Glide 初始化的时候 通过 Registry.append()
添加的,这里我们以网络链接举例的。所以,ModelLoad 的实现类是 HttpGlideUrlLoader
加载器,我们看下它的具体实现:
@Override public LoadData<InputStream> buildLoadData( @NonNull GlideUrl model, int width, int height, @NonNull Options options) { GlideUrl url = model; if (modelCache != null) { url = modelCache.get(model, 0, 0); if (url == null) { modelCache.put(model, 0, 0, model); url = model; } } int timeout = options.get(TIMEOUT); // 看这里,TMD 终于看见Glide 网络加载器了 return new LoadData<>(url, new HttpUrlFetcher(url, timeout)); }
看到是返回的一个HttpUrlFetcher
给加载器。加载器我们拿到了,现在开始加载,返回到刚刚的源码,请看下面:
@Override public boolean startNext() { // ... while (!started && hasNextModelLoader()) { loadData = helper.getLoadData().get(loadDataListIndex++); if (loadData != null && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) { started = true; startNextLoad(loadData); } } return started; } private void startNextLoad(final LoadData<?> toStart) { loadData.fetcher.loadData(...); }
@Override public void loadData(...) { //... //http 请求,返回一个 InputStream 输入流 InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders()); //将 InputStream 以回调形式回调出去 callback.onDataReady(result); //... } private InputStream loadDataWithRedirects(...) { // ... urlConnection = connectionFactory.build(url); for (Map.Entry<String, String> headerEntry : headers.entrySet()) { urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue()); } urlConnection.setConnectTimeout(timeout); urlConnection.setReadTimeout(timeout); urlConnection.setUseCaches(false); urlConnection.setDoInput(true); urlConnection.setInstanceFollowRedirects(false); // Connect explicitly to avoid errors in decoders if connection fails. urlConnection.connect(); // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352. stream = urlConnection.getInputStream(); // ... }
至此,终于找到网络请求了,这里是 HttpURLConnection 作为 Glide 底层成网络请求的。请求成功之后直接返回的是一个输入流,最后会通过 callback.onDataReady(result);
回调到 DecodeJob onDataFetcherReady 函数中。同学们我们跟下回调,回调到 SourceGenerator
loadData.fetcher.loadData(helper.getPriority(), new DataCallback<Object>() { @Override public void onDataReady(@Nullable Object data) { if (isCurrentRequest(toStart)) { //这里需要记住,后面资源准备好之后 ,会回调到这里onDataReadyInternal(toStart, data); } } @Override public void onLoadFailed(@NonNull Exception e) { if (isCurrentRequest(toStart)) {onLoadFailedInternal(toStart, e); } } });
前面调用loadData.fetcher.loadData方法重写了onDataReady,所以有继续调用onDataReadyInternal
void onDataReadyInternal(LoadData<?> loadData, Object data) { DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy(); if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) { dataToCache = data; // We might be being called back on someone else's thread. Before doing anything, we should // reschedule to get back onto Glide's thread. cb.reschedule(); } else {// 由于没有配置缓存,所以继续回调到 DecodeJob --》onDataFetcherRead cb.onDataFetcherReady( loadData.sourceKey, data, loadData.fetcher, loadData.fetcher.getDataSource(), originalKey); } }
@Override public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) { this.currentSourceKey = sourceKey; //当前返回数据的 key this.currentData = data; //返回的数据 this.currentFetcher = fetcher; //返回的数据执行器,这里可以理解为 HttpUrlFetcher this.currentDataSource = dataSource; //数据来源 url this.currentAttemptingKey = attemptedKey; if (Thread.currentThread() != currentThread) { runReason = RunReason.DECODE_DATA; callback.reschedule(this); } else { GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData"); try { //解析返回回来的数据 decodeFromRetrievedData(); } finally { GlideTrace.endSection(); } } } //解析返回的数据 private void decodeFromRetrievedData() { Resource<R> resource = null; try { // 调用 decodeFrom 解析 数据;HttpUrlFetcher , InputStream , currentDataSource resource = decodeFromData(currentFetcher, currentData, currentDataSource); } catch (GlideException e) { e.setLoggingDetails(currentAttemptingKey, currentDataSource); throwables.add(e); } //解析完成后,通知下去 if (resource != null) { notifyEncodeAndRelease(resource, currentDataSource); } else { runGenerators(); } }
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) { ...//通知调用层数据已经装备好了 notifyComplete(result, dataSource); stage = Stage.ENCODE; try { //这里就是将资源磁盘缓存 if (deferredEncodeManager.hasResourceToEncode()) { deferredEncodeManager.encode(diskCacheProvider, options); } } finally { ... }//完成 onEncodeComplete(); } private void notifyComplete(Resource<R> resource, DataSource dataSource) { setNotifiedOrThrow(); // 在 DecodeJob 的构建中, 我们知道这个 Callback 是 EngineJob callback.onResourceReady(resource, dataSource); }}
可以看到上面的 DecodeJob.decodeFromRetrievedData 中主要做了三个处理:
第一个处理:解析返回回来的资源。
第二个处理:拿到解析的资源,如果配置了本地缓存,就缓存到磁盘。
第三个处理:通知上层资源准备就绪,可以使用了。
同学们我们直接看 EngineJob 的 onResourceReady 回调函数:
@Override public void onResourceReady(Resource<R> resource, DataSource dataSource) { synchronized (this) { this.resource = resource; this.dataSource = dataSource; } notifyCallbacksOfResult(); }void notifyCallbacksOfResult() { // ...//回调上层 Engine 任务完成了 engineJobListener.onEngineJobComplete(this, localKey, localResource); //遍历资源回调给 ImageViewTarget for (final ResourceCallbackAndExecutor entry : copy) { entry.executor.execute(new CallResourceReady(entry.cb)); } }
通过上面 EngineJob 的 onResourceReady 回调函数 主要做了 两个处理:
第一个处理:通知上层任务完成。
第二个处理:回调 ImageViewTarget 用于展示数据
private class CallResourceReady implements Runnable { private final ResourceCallback cb; CallResourceReady(ResourceCallback cb) { this.cb = cb; } @Override public void run() { synchronized (EngineJob.this) { if (cbs.contains(cb)) { ... //返回准备好的资源 callCallbackOnResourceReady(cb); removeCallback(cb); } decrementPendingCallbacks(); } } }
@Synthetic synchronized void callCallbackOnResourceReady(ResourceCallback cb) { try { //回调给 SingleRequest cb.onResourceReady(engineResource, dataSource); } catch (Throwable t) { throw new CallbackException(t); } }
@Override public void onResourceReady(Resource<?> resource, DataSource dataSource) { // ... //当资源准备好的时候 onResourceReady((Resource<R>) resource, (R) received, dataSource); // ... } private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) { // ... if (!anyListenerHandledUpdatingTarget) { Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource); //回调给目标 ImageViewTarget 资源准备好了 target.onResourceReady(result, animation); }notifyLoadSuccess(); }
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements Transition.ViewAdapter { @Override public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) { if (transition == null || !transition.transition(resource, this)) { setResourceInternal(resource); } else { maybeUpdateAnimatable(resource); } } private void setResourceInternal(@Nullable Z resource) { setResource(resource); maybeUpdateAnimatable(resource); } protected abstract void setResource(@Nullable Z resource);}
在最开始构建的时候,我们知道只有调用 asBitmap 的时候实现类是 BitmapImageViewTarget
,在这里的测试,并没有调用这个函数,所以它的实现类是 DrawableImageViewTarget
,具体看下它内部实现:
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> { public DrawableImageViewTarget(ImageView view) { super(view); } /** @deprecated Use {@link #waitForLayout()} instead. */ // Public API. @SuppressWarnings({"unused", "deprecation"}) @Deprecated public DrawableImageViewTarget(ImageView view, boolean waitForLayout) { super(view, waitForLayout); } @Override protected void setResource(@Nullable Drawable resource) { view.setImageDrawable(resource); }}
这里看到抽象类中调用了 setResource ,子类实现并调用了 view.setImageDrawable(resource); 图片现在算是真正的显示出来了