Glide analysis (2) - request construction execution phase

background

In the previous article, we learned with()the method of glide, and then continue to study the request construction phase.

1. Request structure

1.1 RequestManager.load()

RequestManager provides a series of overloaded load()methods .

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);
  }

复制代码

The load() method supports multiple input types : bitmap、drawable、string、Uri、Url、resID、File、byte[]字节数组,Object类型. Returns a RequestBuilderobject .

1.1.1 asDrawable() method

  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);
  }
  
复制代码

Create a RequestBuilder object.

img.png

You can see the inheritance relationship of RequestBuilder. RequestBuilderand RequestOptionsare inherited BaseRequestOptions.

Go back load()to the method, and then look at load()the method :

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;
}
复制代码

Internally call loadGeneric()the method :

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();
  }
复制代码

The load() method is RequestBuilderto this.modelassign a value to the member variable of .

1.2.2 asXXX series methods of RequestManager


  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);
  }  
复制代码

So far, we want to summarize that RequestManager not only has asDrawable()methods , but also similar asBitmap(),asGif()ones. They all call the as() method, which returns a RequestBuilder object.

After completing the assignment of the model, let's continue to look at into()the method .

1.3 RequestBuilder.into()

RequestBuilder.java

The into() method also has many overloaded methods, which return a Target object:

 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…

Guess you like

Origin juejin.im/post/7219590039759454265