滑空解析(2)~依頼工事実施フェーズ

バックグラウンド

前回の記事で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 オブジェクトを作成します。

img.png

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() メソッドはRequestBuilderthis.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()方法前,我们先看看 glideContextbuildImageViewTarget() 方法。

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接口的继承关系

img_1.png

好了在得到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;
  }

复制代码

职责:

  1. 调用 buildRequest() 构造request
  2. 如果target中存在之前的请求,则重用
  3. 开始新的请求

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的继承关系

类似类似 img_2.png 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));
      }
    }
  }

复制代码

职责:

  1. 如果没设置model,则走失败流程
  2. 如果指定了宽、高,则直接进入 onSizeReady() 方法
  3. 如果没有指定宽、高,则需要获取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);
  }
复制代码

这里有个一设置的顺序:

  1. 优先展示getFallbackDrawable
  2. 其次是getErrorDrawable
  3. 最后是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 小结

  1. 首先从内存缓存中获取

    • 先从activeResource中获取
    • 如果没有,再从Cache中获取,而Cache是一个 LruResourceCache 来管理的
  2. 内存中没有,则 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.
  }

复制代码

当前 currentGeneratorResourceCacheGenerator 类型。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();
    }
  }
复制代码

总结:

  1. 由于初始化过程中会注册好的registry信息,其中包含modelLoaderRegistry、encoderRegistry、decoderRegistry等等重要成员变量。 DecoderHelper根据model.getClass(), resourceClass, transcodeClass,来获取对应的处理类。
  2. 如果磁盘有缓存文件,则会调用 ByteBufferFileLoader 的buildLoadData()方法,来获取loadData,LoadData对象,该对象重要的成员变量是DataFetcher,最终会调用 fetcher.loadData()方法来 处理。
  3. 如果没有磁盘缓存文件,则继续找下一个 generator,也就是 DataCacheGenerator,此时还是在 runGenerators()方法的while 循环中。

我们可以看看有多少中支持的 ModeLoader 对象: 每一个loader对象都有一个fetch成员与之对应:

img_4.png

第一次,是没有磁盘缓存文件的,因此会走第三步,此时还是在 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);
            }
          }
        });
  }

复制代码

内部会调用 HttpGlideUrlLoaderbuildLoadData()方法,生成 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();
  }
}

复制代码

三、总结

  1. RequestManager.load()得到 RequestBuilder 对象,在调用into()方法,得到 SingleRequest 对象。
  2. 调用 SingleRequest对象 begin()方法,最终等待宽、高确定,在 onSizeReady()中调用engine.load()方法。
  3. load()方法首先从内存缓存中(依次从active、cache两个内存集合)获取资源,如果有则返回。反之,则创建一个 decodeJob 和 engineJob 对象,开始下一阶段。
  4. glide-disk-cahe-1线程开始执行 decodeJob 任务。依次调用 ResourceCacheGenerator(采样后的磁盘缓存文件)、DataCacheGenerator(原始的磁盘缓存文件)、SourceGenerator(远端网络源)来处理。如果有磁盘缓存,则直接返回。
  5. 如果没有磁盘缓存,本质上通过 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());
  }
}
复制代码

至于,后续的处理流程,我们在下篇文章去分析了。

四、参考

blog.yorek.xyz/android/3rd…

juejin.cn/post/688253…

juejin.cn/post/713690…

おすすめ

転載: juejin.im/post/7219590039759454265