バックグラウンド
前回の記事でwith()
グライドの方法を学びましたが、引き続きリクエスト構築フェーズの勉強を続けます。
1. リクエスト構造
1.1 RequestManager.load()
RequestManager は、オーバーロードされた一連のload()
メソッド。
RequestManager.java
@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
@Override
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable File file) {
return asDrawable().load(file);
}
@SuppressWarnings("deprecation")
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return asDrawable().load(resourceId);
}
@SuppressWarnings("deprecation")
@CheckResult
@Override
@Deprecated
public RequestBuilder<Drawable> load(@Nullable URL url) {
return asDrawable().load(url);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable byte[] model) {
return asDrawable().load(model);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
复制代码
load() メソッドは、複数の入力タイプをサポートしています: bitmap、drawable、string、Uri、Url、resID、File、byte[]字节数组,Object类型
。RequestBuilder
オブジェクトを返します。
1.1.1 asDrawable() メソッド
public RequestBuilder<Drawable> asDrawable() {
// 传入Drawable类型
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
// new 一个 RequestBuilder对象, 第三个参数是Drawable.class 类型
return new RequestBuilder<>(glide, this, resourceClass, context);
}
复制代码
RequestBuilder オブジェクトを作成します。
RequestBuilder の継承関係がわかります。RequestBuilder
と継承されRequestOptions
ますBaseRequestOptions
。
load()
メソッドload()
に戻り、 RequestBuilder のメソッドを見てください。
1.2 RequestBuilder.load()
RequestBuilder.java
public RequestBuilder<TranscodeType> load(@Nullable Object model) {
return loadGeneric(model);
}
public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
return loadGeneric(bitmap).apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
public RequestBuilder<TranscodeType> load(@Nullable Drawable drawable) {
return loadGeneric(drawable).apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
public RequestBuilder<TranscodeType> load(@Nullable Uri uri) {
return maybeApplyOptionsResourceUri(uri, loadGeneric(uri));
}
public RequestBuilder<TranscodeType> load(@Nullable File file) {
return loadGeneric(file);
}
public RequestBuilder<TranscodeType> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return applyResourceThemeAndSignature(loadGeneric(resourceId));
}
public RequestBuilder<TranscodeType> load(@Nullable URL url) {
return loadGeneric(url);
}
public RequestBuilder<TranscodeType> load(@Nullable byte[] model) {
RequestBuilder<TranscodeType> result = loadGeneric(model);
if (!result.isDiskCacheStrategySet()) {
result = result.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
if (!result.isSkipMemoryCacheSet()) {
result = result.apply(skipMemoryCacheOf(true /*skipMemoryCache*/));
}
return result;
}
复制代码
loadGeneric()
メソッドを内部的に呼び出します。
1.2.1 loadGeneric()
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
if (isAutoCloneEnabled()) {
return clone().loadGeneric(model);
}
// 赋值model ,这个是Object类型,接收所有输入类型
this.model = model;
isModelSet = true;
return selfOrThrowIfLocked();
}
复制代码
load() メソッドはRequestBuilder
、this.model
のメンバー変数に値を代入することです。
1.2.2 RequestManagerのasXXX系メソッド
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public RequestBuilder<Bitmap> asBitmap() {
return as(Bitmap.class).apply(DECODE_TYPE_BITMAP);
}
public RequestBuilder<GifDrawable> asGif() {
return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
}
public RequestBuilder<File> asFile() {
return as(File.class).apply(skipMemoryCacheOf(true));
}
// 都会调用 RequestBuilder
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
// new 一个 RequestBuilder对象,第三个参数是Drawable.class 类型
return new RequestBuilder<>(glide, this, resourceClass, context);
}
复制代码
これまでのところ、 RequestManager にはasDrawable()
メソッド、同様のasBitmap(),asGif()
メソッドもあるとまとめたいと思います。それらはすべて、RequestBuilder オブジェクトを返す as() メソッドを呼び出します。
モデルの割り当てが完了したら、引き続き RequestBuilder のinto()
メソッド。
1.3 RequestBuilder.into()
RequestBuilder.java
into() メソッドには、ターゲット オブジェクトを返す多くのオーバーロードされたメソッドもあります。
public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
return into(target, null, Executors.mainThreadExecutor());
}
@NonNull
<Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
Executor callbackExecutor) {
return into(target, targetListener, /* options= */ this, callbackExecutor);
}
// 建议使用submit()
@Deprecated
public FutureTarget<TranscodeType> into(int width, int height) {
return submit(width, height);
}
public FutureTarget<TranscodeType> submit(int width, int height) {
final RequestFutureTarget<TranscodeType> target = new RequestFutureTarget<>(width, height);
return into(target, target, Executors.directExecutor());
}
public Target<TranscodeType> preload(int width, int height) {
final PreloadTarget<TranscodeType> target = PreloadTarget.obtain(requestManager, width, height);
return into(target);
}
//@deprecated Use {@link RequestManager#downloadOnly()} and {@link #into(Target)}.
public <Y extends Target<File>> Y downloadOnly(@NonNull Y target) {
return getDownloadOnlyRequest().into(target);
}
// 最终都会调用到这里
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request request = buildRequest(target, targetListener, options, callbackExecutor);
// ...
//返回
return target;
}
复制代码
我们常用的就是 into(view)
这个:
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
// 只有主线程才可以调用
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
// 准备transformation参数
if (!requestOptions.isTransformationSet() // isTransformationSet默认为false
&& requestOptions.isTransformationAllowed() // isTransformationAllowed()一般为true
&& 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.
// 当使用这个RequestBuilder去加载到一个view target,然后又需要加载到另一个target的时候,调用clone()方法可以
// 清除之前一些 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.
}
}
return into(
glideContext.buildImageViewTarget(view, transcodeClass), // 构造接收target
/* targetListener= */ null,
requestOptions,
Executors.mainThreadExecutor()); // callback的时候执行器
}
}
复制代码
调整 Scale Type,清除前一个target的transform参数。
此时,transcodeClass
就是 Drawable.class
。 注意:如果调用 asBitmap()之类的方法,则 transcodeClass 就是 Bitmap.class。
在继续深入into()方法前,我们先看看 glideContext
的 buildImageViewTarget()
方法。
1.3.1 GlideContext.buildImageViewTarget() 方法
GlideContext.java
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
复制代码
imageViewTargetFactory是在 glide初始化阶段在构造方法中,new ImageViewTargetFactory()
得到。
1.3.2 ImageViewTargetFactory.buildTarget()
ImageViewTargetFactory.java
/// viewTarget构造
public class ImageViewTargetFactory {
@NonNull
@SuppressWarnings("unchecked")
public <Z> ViewTarget<ImageView, Z> buildTarget(
@NonNull ImageView view, @NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
// 返回 一个 DrawableImageViewTarget
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
// 不是 Bitmap 或 drawable则 抛出异常
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
复制代码
由于之前我们传入的是Drawable.class,因此,返回 ViewTarget
类型对象是 DrawableImageViewTarget
。
需要注意的是,只有调用into(imageView)这个方法,才会检测 btranscodeClas必须是 Bitmap或者Drawble,其他into()方法是不会的。
1.3.3 target的继承关系
Target接口的继承关系
好了在得到target之后,我们继续深入看 into()
方法:
1.4 继续 into()重载方法
RequestBuilder.java
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target, // 此时就是 DrawableImageViewTarget
@Nullable RequestListener<TranscodeType> targetListener,// 此时为null
BaseRequestOptions<?> options, //
Executor callbackExecutor) { //主线程执行器
// target null判断
Preconditions.checkNotNull(target);
// 如果没有通过load给model赋值,则抛出异常
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
// 1 终于看到构造了请求 Request
Request request = buildRequest(target, targetListener, options, callbackExecutor);
// 获取这个target之前的 request
Request previous = target.getRequest();
// 如果是同一个请求且不跳过内存缓存,怎么判断??应该是重写了equals()和 hashcode() 方法
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
//开始之前的request
previous.begin();
}
// 如果是同一个请求 则直接返回
return target;
}
// 否则, 开启新请求
requestManager.clear(target);
// 给target设置新的 request对象
target.setRequest(request);
// 开始执行请求
requestManager.track(target, request);
return target;
}
复制代码
职责:
- 调用
buildRequest()
构造request - 如果target中存在之前的请求,则重用
- 开始新的请求
1.4.1 buildRequest()构造请求
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
// 调用 buildRequestRecursive
return buildRequestRecursive(
/* requestLock= */ new Object(),
target,
targetListener,
/* parentCoordinator= */ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
private Request buildRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator, // parentCoordinator是null
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
// Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
ErrorRequestCoordinator errorRequestCoordinator = null;
// errorBuilder 是null
if (errorBuilder != null) {
errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
// 构造
Request mainRequest =
buildThumbnailRequestRecursive(
requestLock,
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
// errorRequestCoordinator=null 成立 ,直接返回
if (errorRequestCoordinator == null) {
return mainRequest;
}
int errorOverrideWidth = errorBuilder.getOverrideWidth();
int errorOverrideHeight = errorBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight) && !errorBuilder.isValidOverride()) {
errorOverrideWidth = requestOptions.getOverrideWidth();
errorOverrideHeight = requestOptions.getOverrideHeight();
}
Request errorRequest =
errorBuilder.buildRequestRecursive(
requestLock,
target,
targetListener,
errorRequestCoordinator,
errorBuilder.transitionOptions,
errorBuilder.getPriority(),
errorOverrideWidth,
errorOverrideHeight,
errorBuilder,
callbackExecutor);
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
复制代码
1.4.1.1 buildThumbnailRequestRecursive()
private Request buildThumbnailRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
// 不走这里
if (thumbnailBuilder != null) {
// Recursive case: contains a potentially recursive thumbnail request builder.
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()");
}
TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
thumbnailBuilder.transitionOptions;
// Apply our transition by default to thumbnail requests but avoid overriding custom options
// that may have been applied on the thumbnail request explicitly.
if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
thumbTransitionOptions = transitionOptions;
}
Priority thumbPriority =
thumbnailBuilder.isPrioritySet()
? thumbnailBuilder.getPriority()
: getThumbnailPriority(priority);
int thumbOverrideWidth = thumbnailBuilder.getOverrideWidth();
int thumbOverrideHeight = thumbnailBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !thumbnailBuilder.isValidOverride()) {
thumbOverrideWidth = requestOptions.getOverrideWidth();
thumbOverrideHeight = requestOptions.getOverrideHeight();
}
ThumbnailRequestCoordinator coordinator =
new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
Request fullRequest =
obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
isThumbnailBuilt = true;
// Recursively generate thumbnail requests.
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(
requestLock,
target,
targetListener,
coordinator,
thumbTransitionOptions,
thumbPriority,
thumbOverrideWidth,
thumbOverrideHeight,
thumbnailBuilder,
callbackExecutor);
isThumbnailBuilt = false;
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
// 不走这里
} else if (thumbSizeMultiplier != null) {
// Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
ThumbnailRequestCoordinator coordinator =
new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
Request fullRequest =
obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
BaseRequestOptions<?> thumbnailOptions =
requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);
Request thumbnailRequest =
obtainRequest(
requestLock,
target,
targetListener,
thumbnailOptions,
coordinator,
transitionOptions,
getThumbnailPriority(priority),
overrideWidth,
overrideHeight,
callbackExecutor);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
// 走的这里
// Base case: no thumbnail.
return obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
}
}
复制代码
此时会走else逻辑,不管走哪个分支,最终都会调用 obtainRequest()
方法。
1.4.1.2 obtainRequest()
private Request obtainRequest(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
return SingleRequest.obtain(
context,
glideContext,
requestLock,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
复制代码
到这里,我们得到了request请求的具体实现类。 SingleRequest对象
。 obtain()方法会new SingleRequest 对象。
1.4.2 target.setRequest(request);
private void setTag(@Nullable Object tag) {
view.setTag(VIEW_TAG_ID, tag);
}
复制代码
最后调用的是view的setTag()方法。
1.4.3 requestManager.track()
RequestManager.java
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
//跟踪target的生命周期
targetTracker.track(target);
//跟踪请求的,用来控制重新开始、完成、失败、取消请求
// 开始网络请求
requestTracker.runRequest(request);
}
复制代码
到这里,我们构造了请求对象request,同时准备开始发起请求。
targetTracker
是 RequestManager的成员变量。每一个页面对应一个requestManager对象。 requestTracker
也是RequestManager的成员变量。用来发起、跟踪请求。
1.5 TargetTracker.track()
TargetTracker.java
public final class TargetTracker implements LifecycleListener {
private final Set<Target<?>> targets =
Collections.newSetFromMap(new WeakHashMap<Target<?>, Boolean>());
public void track(@NonNull Target<?> target) {
// 加入到 targets set集合,没做啥
targets.add(target);
}
//...
}
复制代码
1.6 requestTracker.runRequest(request)
RequestTracker.java
public void runRequest(@NonNull Request request) {
// 添加到请求队列
requests.add(request);
if (!isPaused) {
// 开始
request.begin();
} else {
//
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
// 如果暂停,则加入到pending队列
pendingRequests.add(request);
}
}
复制代码
1.7 request的继承关系
类似类似 Request 请求的继承关系。
至此,Request构造部分已经完成,接下来就是执行过程了。
继续看看request的 begin()
方法。 Request的实现类是 SingleRequest
。
二、 SingleRequest.begin()
SingleRequest.java
public void begin() {
synchronized (requestLock) {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
// model==null,也就意味着load()方法传入的参数为null。因此进入失败流程
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
// Only log at more verbose log levels if the user has set a fallback drawable, because
// fallback Drawables indicate the user expects null models occasionally.
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 we're restarted after we're complete (usually via something like a notifyDataSetChanged
// that starts an identical request into the same Target or View), we can simply use the
// resource and size we retrieved the last time around and skip obtaining a new size, starting
// a new load etc. This does mean that users who want to restart a load because they expect
// that the view size has changed will need to explicitly clear the View or Target before
// starting the new load.
// 如果已经加载完成,则直接返回内存中的缓存
if (status == Status.COMPLETE) {
onResourceReady(
resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
return;
}
// Restarts for requests that are neither complete nor running can be treated as new requests
// and can run again from the beginning.
experimentalNotifyRequestStarted(model);
// 准备开始执行请求
cookie = GlideTrace.beginSectionAsync(TAG);
// 进入等待size的状态
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// 如果指定了overrideWidth和overrideHeight,则开始加载
onSizeReady(overrideWidth, overrideHeight);
} else {
// 如果没有指定overrideWidth和overrideHeight,则先获取target的size,后续会回调到 onSizeReady 方法
// 也就是说等拿到最终draw的 width和height才去加载图片
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
//回调 onLoadStarted()方法
target.onLoadStarted(getPlaceholderDrawable());
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
}
复制代码
职责:
- 如果没设置model,则走失败流程
- 如果指定了宽、高,则直接进入
onSizeReady()
方法 - 如果没有指定宽、高,则需要获取view的宽高,等确定最终宽高后,在进入
onSizeReady()
方法
2.1 model为null的 onLoadFailed()回调
private void onLoadFailed(GlideException e, int maxLogLevel) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
e.setOrigin(requestOrigin);
int logLevel = glideContext.getLogLevel();
if (logLevel <= maxLogLevel) {
Log.w(
GLIDE_TAG,
"Load failed for [" + model + "] with dimensions [" + width + "x" + height + "]",
e);
if (logLevel <= Log.INFO) {
e.logRootCauses(GLIDE_TAG);
}
}
loadStatus = null;
status = Status.FAILED;
notifyRequestCoordinatorLoadFailed();
isCallingCallbacks = true;
try {
// TODO: what if this is a thumbnail request?
boolean anyListenerHandledUpdatingTarget = false;
if (requestListeners != null) {
for (RequestListener<R> listener : requestListeners) {
anyListenerHandledUpdatingTarget |=
listener.onLoadFailed(e, model, target, isFirstReadyResource());
}
}
anyListenerHandledUpdatingTarget |=
targetListener != null
&& targetListener.onLoadFailed(e, model, target, isFirstReadyResource());
if (!anyListenerHandledUpdatingTarget) {
// 失败时的图片展示
setErrorPlaceholder();
}
} finally {
isCallingCallbacks = false;
}
GlideTrace.endSectionAsync(TAG, cookie);
}
}
复制代码
2.1.1 setErrorPlaceholder()
@GuardedBy("requestLock")
private void setErrorPlaceholder() {
if (!canNotifyStatusChanged()) {
return;
}
Drawable error = null;
if (model == null) {
error = getFallbackDrawable();
}
// Either the model isn't null, or there was no fallback drawable set.
if (error == null) {
error = getErrorDrawable();
}
// The model isn't null, no fallback drawable was set or no error drawable was set.
if (error == null) {
error = getPlaceholderDrawable();
}
target.onLoadFailed(error);
}
复制代码
这里有个一设置的顺序:
- 优先展示getFallbackDrawable
- 其次是getErrorDrawable
- 最后是getPlaceholderDrawable
回到 begin()
方法,也就是说我们必须要等拿到最终draw阶段的 width和height
才去加载图片,此时状态为 WAITING_FOR_SIZE
, 看 onSizeReady()。
2.2 SingleRequest.onSizeReady()
@Override
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
if (IS_VERBOSE_LOGGABLE) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
//状态修改为running
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
if (IS_VERBOSE_LOGGABLE) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
// 调用 engine 的load()方法,
loadStatus =
engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this,
callbackExecutor);
// This is a hack that's only useful for testing right now where loads complete synchronously
// even though under any executor running on any thread but the main thread, the load would
// have completed asynchronously.
if (status != Status.RUNNING) {
loadStatus = null;
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
}
复制代码
调用 engine 的 load()
方法, engine 我们之前分析过,是在 GlideBuilder的 build()
方法中创建的。
2.3 Engine.load()
Engine.java
<p>Active resources are those that have been provided to at least one request and have not yet
* been released. Once all consumers of a resource have released that resource, the resource then
* goes to cache. If the resource is ever returned to a new consumer from cache, it is re-added to
* the active resources. If the resource is evicted from the cache, its resources are recycled and
* re-used if possible and the resource is discarded. There is no strict requirement that
* consumers release their resources so active resources are held weakly.
提供给一个或多个请求且没有被释放的资源被称为active资源。一旦所有的消费者都释放了该资源,该资源就会被放入cache中。
如果有请求将资源从cache中取出,它会被重新添加到active资源中。如果一个资源从cache中移除,其本身会被discard,其内部拥有的资源将会回收或者在可能的情况下重用。
并没有严格要求消费者一定要释放它们的资源,所以active资源会以弱引用的方式保持。
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb, // cb就是singleRequest本身
Executor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
// 构建一个key,作为唯一标识,。EngineKey肯定重写hashcode方法和equals方法
EngineKey key =
keyFactory.buildKey(
model, // url地址
signature, //
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
// 根据key,从内存中获取内存缓存,如何获取的?后续再学习
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
// 内存中没有,则准备等待一个存在的或者开启新 job任务
return waitForExistingOrStartNewJob(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
options,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache,
cb,
callbackExecutor,
key,
startTime);
}
}
// Avoid calling back while holding the engine lock, doing so makes it easier for callers to
// deadlock.
// 内存中有,则回调加载成功
cb.onResourceReady(
memoryResource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
return null;
}
复制代码
2.3.1 内存获取策略 loadFromMemory()
@Nullable
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
if (!isMemoryCacheable) {
return null;
}
// 从active resources 中获取
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return active;
}
// 如果active没有,则从cache中获取
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return cached;
}
return null;
}
//
ActiveResources activeResources;成员变量
@Nullable
private EngineResource<?> loadFromActiveResources(Key key) {
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
retu
rn active;
}
复制代码
2.3.2 ActiveResources.get(key)
ActiveResources.java
@VisibleForTesting final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
@Nullable
synchronized EngineResource<?> get(Key key) {
ResourceWeakReference activeRef = activeEngineResources.get(key);
if (activeRef == null) {
return null;
}
EngineResource<?> active = activeRef.get();
if (active == null) {
cleanupActiveReference(activeRef);
}
return active;
}
复制代码
什么时候存进去的? 应该是从网络获取到的时候?
2.3.3 Engine.loadFromCache
private EngineResource<?> loadFromCache(Key key) {
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
activeResources.activate(key, cached);
}
return cached;
}
private EngineResource<?> getEngineResourceFromCache(Key key) {
///从glideBuilder中可以知道这个 cache对象,默认是 LruResourceCache。
Resource<?> cached = cache.remove(key);
final EngineResource<?> result;
if (cached == null) {
result = null;
} else if (cached instanceof EngineResource) {
// Save an object allocation if we've cached an EngineResource (the typical case).
result = (EngineResource<?>) cached;
} else {
result =
new EngineResource<>(
cached,
/* isMemoryCacheable= */ true,
/* isRecyclable= */ true,
key,
/* listener= */ this);
}
return result;
}
复制代码
LruResourceCache
对象的内部通过 private final Map<T, Entry<Y>> cache = new LinkedHashMap(100, 0.75f, true)
;实现了lru功能。
2.3.4 小结
-
首先从内存缓存中获取
- 先从activeResource中获取
- 如果没有,再从Cache中获取,而Cache是一个 LruResourceCache 来管理的
-
内存中没有,则
waitForExistingOrStartNewJob()
2.4 waitForExistingOrStartNewJob()
private <R> LoadStatus waitForExistingOrStartNewJob(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor,
EngineKey key,
long startTime) {
// 先从正在执行的jobs中 获取,第一次,肯定没有
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对象,
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
// 构建 DecodeJob 对象,但是pools的好处是??
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
// 存入正在running的 jobs
jobs.put(key, engineJob);
//cb 是request
engineJob.addCallback(cb, callbackExecutor);
// 传入decodejob,开始加载
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
复制代码
engineJob和decodeJob都是通过 factory
构造出来,里面通过 pool
来缓存了 engineJob 和 decodeJob 对象。缓存大小都是150个,本质上是一个Object[] 数组
来缓存。 并且是线程安全的。
我们以engineJob为例,看看:
@VisibleForTesting
static class EngineJobFactory {
@Synthetic final GlideExecutor diskCacheExecutor;
@Synthetic final GlideExecutor sourceExecutor;
@Synthetic final GlideExecutor sourceUnlimitedExecutor;
@Synthetic final GlideExecutor animationExecutor;
@Synthetic final EngineJobListener engineJobListener;
@Synthetic final ResourceListener resourceListener;
@Synthetic
final Pools.Pool<EngineJob<?>> pool =
FactoryPools.threadSafe( // 加了同步锁
JOB_POOL_SIZE, // 150
new FactoryPools.Factory<EngineJob<?>>() {
@Override
public EngineJob<?> create() {
// 如果为空,则会调用create方法创建
return new EngineJob<>(
diskCacheExecutor,
sourceExecutor,
sourceUnlimitedExecutor,
animationExecutor,
engineJobListener,
resourceListener,
pool);
}
});
EngineJobFactory(
GlideExecutor diskCacheExecutor,
GlideExecutor sourceExecutor,
GlideExecutor sourceUnlimitedExecutor,
GlideExecutor animationExecutor,
EngineJobListener engineJobListener,
ResourceListener resourceListener) {
this.diskCacheExecutor = diskCacheExecutor;
this.sourceExecutor = sourceExecutor;
this.sourceUnlimitedExecutor = sourceUnlimitedExecutor;
this.animationExecutor = animationExecutor;
this.engineJobListener = engineJobListener;
this.resourceListener = resourceListener;
}
@VisibleForTesting
void shutdown() {
Executors.shutdownAndAwaitTermination(diskCacheExecutor);
Executors.shutdownAndAwaitTermination(sourceExecutor);
Executors.shutdownAndAwaitTermination(sourceUnlimitedExecutor);
Executors.shutdownAndAwaitTermination(animationExecutor);
}
@SuppressWarnings("unchecked")
<R> EngineJob<R> build(
Key key,
boolean isMemoryCacheable,
boolean useUnlimitedSourceGeneratorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache) {
EngineJob<R> result = Preconditions.checkNotNull((EngineJob<R>) pool.acquire());
// 内部会调用到 EngineJob 的init方法,
return result.init(
key,
isMemoryCacheable,
useUnlimitedSourceGeneratorPool,
useAnimationPool,
onlyRetrieveFromCache);
}
}
复制代码
2.5 engineJob.start()
EngineJob.java
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
// willDecodeFromCache会返回true,表示会尝试使用磁盘缓存的线程池
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
// 这里,执行的是decodeJob
// 此时的线程是glide-disk-cache-1线程
executor.execute(decodeJob);
}
/**
DecodeJob.java
* Returns true if this job will attempt to decode a resource from the disk cache, and false if it
* will always decode from source.
*/
boolean willDecodeFromCache() {
// 这里使用到了状态机模式
Stage firstStage = getNextStage(Stage.INITIALIZE);
return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
}
复制代码
这里,执行的是 decodeJob
,因此看看 DecodeJob 的run()
方法。
2.6 DecodeJob.run()
DecodeJob.java
class DecodeJob<R>
implements DataFetcherGenerator.FetcherReadyCallback,
Runnable,
Comparable<DecodeJob<?>>,
Poolable {
@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(reason=%s, model=%s)", runReason, 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 (CallbackException e) {
// If a callback not controlled by Glide throws an exception, we should avoid the Glide
// specific debug logic below.
throw e;
} 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;
}
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();
}
}
//...
}
复制代码
2.7 runWrapped()
//
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//此时返回的stage RESOURCE_CACHE
stage = getNextStage(Stage.INITIALIZE);
//得到 ResourceCacheGenerator
currentGenerator = getNextGenerator();
//开始执行generators
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:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE
: getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// Skip loading from source if the user opted to only retrieve the resource from cache.
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);
}
}
复制代码
继续看 runGenerators()
方法
2.8 DecodeJob.runGenerators()
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
// 遍历查找能够处理该job的 generator。
// currentGenerator 当前是 ResourceCacheGenerator。
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) { // 判断currentGenerator的 startNext()是否能够处理
//如果不能处理则 遍历下一个stage、currentGenerator 的值
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
// 会重新提交到线程池中运行
if (stage == Stage.SOURCE) {
reschedule(RunReason.SWITCH_TO_SOURCE_SERVICE);
return;
}
}
// 如果全部遍历完,还是没有找到能够处理该job的 generator,则放弃,回调失败。
// We've run out of stages and generators, give up.
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
// Otherwise a generator started a new load and we expect to be called back in onDataFetcherReady.
}
复制代码
当前 currentGenerator
是 ResourceCacheGenerator
类型。runGenerators()的职责就是: 从 ResourceCacheGenerator、DataCacheGenerator、SourceGenerator
三个生成器按顺序去处理。
generator生成器 有三种:
case RESOURCE_CACHE:
// 获取transform、clip裁剪、采样后的缓存文件
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
// 获取没有处理的原始缓存文件
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
// 获取原始数据
return new SourceGenerator(decodeHelper, this);
复制代码
2.9 ResourceCacheGenerator.startNext()
public boolean startNext() {
GlideTrace.beginSection("ResourceCacheGenerator.startNext");
try {
// 获取glide初始化时候注册的所有 CacheKey, 当load(url)的时候就是GlideUrl对象,且只有一个元素 size=1
List<Key> sourceIds = helper.getCacheKeys();
if (sourceIds.isEmpty()) {
return false;
}
/// 获取glide初始化过程中,注册过的资源class集合
//Bitmap、BitmapDrawable、GifDrawable
List<Class<?>> resourceClasses = helper.getRegisteredResourceClasses();
if (resourceClasses.isEmpty()) {
if (File.class.equals(helper.getTranscodeClass())) {
return false;
}
throw new IllegalStateException(
"Failed to find any load path from "
+ helper.getModelClass()
+ " to "
+ helper.getTranscodeClass());
}
// 第一次为null
while (modelLoaders == null || !hasNextModelLoader()) {
// 更新 resourceClassIndex
resourceClassIndex++;
if (resourceClassIndex >= resourceClasses.size()) {
// 这里表示下标为0的sourceIds集合,没法处理,则找下标为1的key,但是sourceIds此时的size=1,因此直接进入return false; 后续代码不走了
sourceIdIndex++;
if (sourceIdIndex >= sourceIds.size()) {
return false;
}
resourceClassIndex = 0;
}
一个sourceIdIndex对应 一个List的resourceClass,分别遍历
Key sourceId = sourceIds.get(sourceIdIndex);
// 得到class对象
Class<?> resourceClass = resourceClasses.get(resourceClassIndex);
// transform
Transformation<?> transformation = helper.getTransformation(resourceClass);
// PMD.AvoidInstantiatingObjectsInLoops Each iteration is comparatively expensive anyway,
// we only run until the first one succeeds, the loop runs for only a limited
// number of iterations on the order of 10-20 in the worst case.
currentKey =
new ResourceCacheKey( // NOPMD AvoidInstantiatingObjectsInLoops
helper.getArrayPool(),
sourceId,
helper.getSignature(),
helper.getWidth(),
helper.getHeight(),
transformation,
resourceClass,
helper.getOptions());
// 根据key获取磁盘缓存
cacheFile = helper.getDiskCache().get(currentKey);
// 如果disk缓存存在
if (cacheFile != null) {
sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
// 不管是否有缓存都会走这里,
//如果有缓存,则 hasNextModelLoader()会返回true
//没有缓存,不进入下面的while循环,表示不能处理,直接return false结束。
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
// 得到 modelLoader,
[ByteBufferFileLoader, FileLoader, FileLoader, UnitModelLoader]
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
/// buildLoadData 是哪个呢?
// 创建loadData 对象,这里会创建出网络请求的对象fetch
//LoadData对象,该对象重要的成员变量是DataFetcher;
loadData =
modelLoader.buildLoadData(
cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
// 标记开始
started = true;
// fetch 开始加载
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
} finally {
GlideTrace.endSection();
}
}
复制代码
总结:
- 由于初始化过程中会注册好的registry信息,其中包含modelLoaderRegistry、encoderRegistry、decoderRegistry等等重要成员变量。 DecoderHelper根据model.getClass(), resourceClass, transcodeClass,来获取对应的处理类。
如果磁盘有缓存文件
,则会调用 ByteBufferFileLoader 的buildLoadData()方法,来获取loadData,LoadData对象,该对象重要的成员变量是DataFetcher,最终会调用 fetcher.loadData()方法来 处理。- 如果没有磁盘缓存文件,
则继续找下一个 generator
,也就是DataCacheGenerator
,此时还是在 runGenerators()方法的while 循环中。
我们可以看看有多少中支持的 ModeLoader 对象: 每一个loader对象都有一个fetch成员与之对应:
第一次,是没有磁盘缓存文件的,因此会走第三步,此时还是在 runGenerators()方法的while 循环中。
2.10 DataCacheGenerator.startNext()方法
DataCacheGenerator.java
public boolean startNext() {
GlideTrace.beginSection("DataCacheGenerator.startNext");
try {
while (modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if (sourceIdIndex >= cacheKeys.size()) {
return false;
}
Key sourceId = cacheKeys.get(sourceIdIndex);
// PMD.AvoidInstantiatingObjectsInLoops The loop iterates a limited number of times
// and the actions it performs are much more expensive than a single allocation.
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
cacheFile = helper.getDiskCache().get(originalKey);
if (cacheFile != null) {
this.sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(
cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
} finally {
GlideTrace.endSection();
}
}
复制代码
也是没有缓存,所以继续下一个 generator,SourceGenerator
:
2.11 SourceGenerator.startNext()
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
try {
// 第一次 没有缓存
boolean isDataInCache = cacheData(data);
// If we failed to write the data to cache, the cacheData method will try to decode the
// original data directly instead of going through the disk cache. Since cacheData has
// already called our callback at this point, there's nothing more to do but return.
if (!isDataInCache) {
return true;
}
// If we were able to write the data to cache successfully, we now need to proceed to call
// the sourceCacheGenerator below to load the data from cache.
} catch (IOException e) {
// An IOException means we weren't able to write data to cache or we weren't able to rewind
// it after a disk cache write failed. In either case we can just move on and try the next
// fetch below.
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to properly rewind or write data to cache", e);
}
}
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
// 此时 调用 HttpGlideUrlLoader 的loadData,
while (!started && hasNextModelLoader()) {
// 内部会调用 HttpGlideUrlLoader的 buildLoadData()方法,生成HttpUrlFetcher 对象
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
// 开始调用 HttpUrlFetcher 对象加载
startNextLoad(loadData);
}
}
return started;
}
private void startNextLoad(final LoadData<?> toStart) {
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);
}
}
});
}
复制代码
内部会调用 HttpGlideUrlLoader
的 buildLoadData()
方法,生成 HttpUrlFetcher
对象。
2.12 HttpUrlFetcher.loadData()
HttpUrlFetcher.java
@Override
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
// 从网络得到输入流 结果result
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
// 回调流的结果,这个 callback是MultiModelLoader
callback.onDataReady(result);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data for url", e);
}
callback.onLoadFailed(e);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
}
}
复制代码
2.12.1 loadDataWithRedirects() 重定向
private InputStream loadDataWithRedirects(
URL url, int redirects, URL lastUrl, Map<String, String> headers) throws HttpException {
if (redirects >= MAXIMUM_REDIRECTS) {
throw new HttpException(
"Too many (> " + MAXIMUM_REDIRECTS + ") redirects!", INVALID_STATUS_CODE);
} else {
// Comparing the URLs using .equals performs additional network I/O and is generally broken.
// See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
try {
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
throw new HttpException("In re-direct loop", INVALID_STATUS_CODE);
}
} catch (URISyntaxException e) {
// Do nothing, this is best effort.
}
}
urlConnection = buildAndConfigureConnection(url, headers);
try {
// 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();
} catch (IOException e) {
throw new HttpException(
"Failed to connect or obtain data", getHttpStatusCodeOrInvalid(urlConnection), e);
}
if (isCancelled) {
return null;
}
final int statusCode = getHttpStatusCodeOrInvalid(urlConnection);
if (isHttpOk(statusCode)) {
return getStreamForSuccessfulRequest(urlConnection);
} else if (isHttpRedirect(statusCode)) {
String redirectUrlString = urlConnection.getHeaderField(REDIRECT_HEADER_FIELD);
if (TextUtils.isEmpty(redirectUrlString)) {
throw new HttpException("Received empty or null redirect url", statusCode);
}
URL redirectUrl;
try {
redirectUrl = new URL(url, redirectUrlString);
} catch (MalformedURLException e) {
throw new HttpException("Bad redirect url: " + redirectUrlString, statusCode, e);
}
// Closing the stream specifically is required to avoid leaking ResponseBodys in addition
// to disconnecting the url connection below. See #2352.
cleanup();
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else if (statusCode == INVALID_STATUS_CODE) {
throw new HttpException(statusCode);
} else {
try {
throw new HttpException(urlConnection.getResponseMessage(), statusCode);
} catch (IOException e) {
throw new HttpException("Failed to get a response message", statusCode, e);
}
}
}
// 构造一个 HttpURLConnection
private HttpURLConnection buildAndConfigureConnection(URL url, Map<String, String> headers)
throws HttpException {
HttpURLConnection urlConnection;
try {
urlConnection = connectionFactory.build(url);
} catch (IOException e) {
throw new HttpException("URL.openConnection threw", /* statusCode= */ 0, e);
}
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);
// Stop the urlConnection instance of HttpUrlConnection from following redirects so that
// redirects will be handled by recursive calls to this method, loadDataWithRedirects.
urlConnection.setInstanceFollowRedirects(false);
return urlConnection;
}
复制代码
代码很清晰,通过构造一个 HttpURLConnection 来发起网络请求。
2.13 结果返回后的处理 onDataReady()
callback是 MultiModelLoader
:
2.13.1 MultiModelLoader.onDataReady()
MultiModelLoader.jva
public void onDataReady(@Nullable Data data) {
if (data != null) {
// 这个callback是 SourceGenerator的匿名内部对象。
callback.onDataReady(data);
} else {
startNextOrFail();
}
}
复制代码
三、总结
- RequestManager.load()得到
RequestBuilder
对象,在调用into()方法,得到SingleRequest
对象。 - 调用 SingleRequest对象
begin()
方法,最终等待宽、高确定,在onSizeReady()
中调用engine.load()方法。 load()
方法首先从内存缓存中(依次从active、cache
两个内存集合)获取资源,如果有则返回。反之,则创建一个 decodeJob 和engineJob
对象,开始下一阶段。- glide-disk-cahe-1线程开始执行 decodeJob 任务。依次调用
ResourceCacheGenerator
(采样后的磁盘缓存文件)、DataCacheGenerator
(原始的磁盘缓存文件)、SourceGenerator
(远端网络源)来处理。如果有磁盘缓存,则直接返回。 - 如果没有磁盘缓存,本质上通过
HttpURLConnection
从网络下载,当然这是默认行为,我们可以通过registry.replace()
方法来替换为我们想要的网络库。如:
@GlideModule
public final class OkHttpLibraryGlideModule extends LibraryGlideModule {
@Override
public void registerComponents(
@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
}
}
复制代码
至于,后续的处理流程,我们在下篇文章去分析了。