加载图片(解码、转码)
在加载远程图片后,会返回 inputStream
,并会调用 decodeFromRetrievedData
方法进行解码处理。
private void decodeFromRetrievedData() {
Resource<R> resource = null;
try {
// 关键代码,解码数据
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
// 处理 resource
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
该方法先通过 decodeFromData
方法来获取解码后的数据,然后调用 notifyEncodeAndRelease
方法来通知处理。 decodeFromData
方法里面又会调用 decodeFromFetcher
方法,如下:
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
throws GlideException {
// LoadPath对象其实是根据我们传入的处理数据来返回特定的数据解码转码处理器对象,即用来解码和转码的。
LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
return runLoadPath(data, dataSource, path);
}
该方法主要返回一个包装了解码和转码器对象的 LoadPath
对象。具体的解码和转码器对象的类型由我们传入的处理数据类型来通过注册表获取到的。然后会调用 runLoadPath
方法,该方法里面会调用 LoadPath
对象的 load
方法,最后会调用 DecodePath
的 decode
方法进行解码处理:
// DecodePath.java
public Resource<Transcode> decode(
DataRewinder<DataType> rewinder,
int width,
int height,
@NonNull Options options,
DecodeCallback<ResourceType> callback)
throws GlideException {
// 调用 decodeResource 进行解码,最终返回可能是 BitmapResource 对象,看具体类型
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
// 这里会回调 DecodeJob 的 onResourceDecoded 方法,最终返回需要转码的类型
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
// 转码 BitmapDrawableTranscoder,最终返回 LazyBitmapDrawableResource
return transcoder.transcode(transformed, options);
}
该方法分为 3 步来进行:
- 调用 decodeResource 方法进行解码处理,因为我们这里需要的是
Drawable
类型,所以这个方法最终会通过StreamBitmapDecoder
解码器来解码成一个BitmapResource
对象。 - 回调
DecodeJob
的onResourceDecoded
方法,最终返回需要转码的类型。 - 通过
BitmapDrawableTranscoder
对象进行转码处理,最终会返回LazyBitmapDrawableResource
对象。
对数据进行解码和转码处理后,由上述 decodeFromRetrievedData
方法可知,会调用 notifyEncodeAndRelease
来通知进行编码等处理,该方法里面又会调用 notifyComplete
方法,如下:
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
// 回调 EngineJob 对象的 onResourceReady
callback.onResourceReady(resource, dataSource);
}
该方法最后会回调如下代码:
for (final ResourceCallbackAndExecutor entry : copy) {
// 切换到主线程进行资源回调
entry.executor.execute(new CallResourceReady(entry.cb));
}
会在主线程回调 CallResourceReady
这个 runnable
对象,最后会回调 SingleRequest
对象的 onResourceReady
方法。
// SingleRequest.java
public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
loadStatus = null;
if (resource == null) {
// 错误回调
onLoadFailed(exception);
return;
}
// 调用 LazyBitmapDrawableResource 对象 的 get 方法,返回 BitmapDrawable 对象
Object received = resource.get();
if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
releaseResource(resource);
// 错误回调
onLoadFailed(exception);
return;
}
if (!canSetResource()) {
releaseResource(resource);
status = Status.COMPLETE;
return;
}
// 关键代码
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
上述方法如果有数据异常,会回调 onLoadFailed
方法,正常情况下会拿到 BitmapDrawable
对象并传入重载的 onResourceReady
方法。
private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
isCallingCallbacks = true;
try {
boolean anyListenerHandledUpdatingTarget = false;
// 回调监听器
if (requestListeners != null) {
for (RequestListener<R> listener : requestListeners) {
anyListenerHandledUpdatingTarget |=
listener.onResourceReady(result, model, target, dataSource, isFirstResource);
}
}
anyListenerHandledUpdatingTarget |=
targetListener != null
&& targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);
// 如果监听器返回的是 true ,后面就不处理了,让用户自己处理
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
// 回调 target (DrawableImageViewTarget)的 onResourceReady 方法
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
上述方法最终会回调 ImageViewTarget
的 onResourceReady
方法,该方法会再调用 ImageViewTarget
对象 setResourceInternal
方法,setResourceInternal
方法最终setResource方法,setResource
在 ImageViewTarget
对象是抽象方法,它在 DrawableImageViewTarget
对象中实现,代码如下:
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) {
// 这是一个抽象方法,在 DrawableImageViewTarget 对象中有实现
setResource(resource);
maybeUpdateAnimatable(resource);
}
// DrawableImageViewTarget.java
protected void setResource(@Nullable Drawable resource) {
// 显示 Drawable
view.setImageDrawable(resource);
}
至此,整个加载流程全部分析完毕,我们回过头看一下最初的调用:
Glide.with(this).load(url).into(mImageView);
就这样一行简单的调用,底层做的工作量真的是巨大的。