Glide 源码阅览笔记(三)

在榜首篇文章中我简略介绍了Glide实例的创立过程,要点介绍了Glide的内存缓存完结和磁盘的缓存完结:Glide 源码阅览笔记(一)

在第二篇文章中介绍了 Glide 对生命周期的办理: Glide 源码阅览笔记(二)

今日咱们持续今日的内容。

源码阅览基于Glide 4.16.0版本

Reqeust 和 RequestCoordinator

Request 比较好了解,它便是一个图片加载的使命。RequestCoordinator 它也是继承于 Request,它是用来和谐它内部的多个 Request,这么说比较抽象。我这儿简略举一个比如。咱们能够在运用 Glide 时,增加一个反常时恳求的使命,当主使命加载失利时 Glide 就会去加载这个反常时恳求的使命。例如以下代码:

val errorRequestBuilder = Glide.with(this)
    .load("")
Glide.with(this)
    .load("https://www.6hu.cc/wp-content/uploads/2024/01/230444-xgqIme.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240")
    .error(errorRequestBuilder)
    .into(findViewById<ImageView>(R.id.my_iv))

其间怎样和谐主 Request 与过错相关的 Request,便是 ErrorRequestCoordinator 的工作,它的工作原理十分简略,首先触发主 Request,当它恳求失利时再去加载反常的 Request。相似原理的还有 ThumbnailRequestCoordinator,它是和谐缩略图加载的 RequestCoordinator。后边的代码剖析中咱们都能看到他们。经过 RequestCoordinator 能够把单个 Request 构建成一个 Request 的恳求树,能够用这个恳求树来履行杂乱的恳求逻辑。

咱们在运用 Glide 构建完 RequestBuilder 后,会经过 into() 办法把终究的成果烘托到对应 ImageView (当然咱们也能够不烘托到 ImageView 中,这需求咱们自定义)。所以咱们也以 RequestBuilder#into() 办法作为今日剖析的入口函数:

  @NonNull
  public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    // 校验必须在主线程
    Util.assertMainThread();
    Preconditions.checkNotNull(view);
    BaseRequestOptions<?> requestOptions = this;
    // 假如没有设置图片的裁剪办法,依据 ImageView 的 ScaleType 来核算。
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      // Clone in this method so that if we use this RequestBuilder to load into a View and then
      // into a different target, we don't retain the transformation applied based on the previous
      // View's scale type.
      // 核算裁剪办法
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions = requestOptions.clone().optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions = requestOptions.clone().optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.
      }
    }
    return into(
        // 将 ImageView 封装成 Target
        glideContext.buildImageViewTarget(view, transcodeClass),
        /* targetListener= */ null,
        requestOptions,
        // 回调线程设置成主线程
        Executors.mainThreadExecutor());
  }

简略阐明下上面的代码:

  1. into() 办法必须在主线程调用。
  2. 假如 RequestBuilder 没有设置裁剪办法,需求经过 ImageView#getScaleType() 来核算,处理裁剪办法的类是 Transformations,它被保存在 options 中,后边咱们会再看到它的呈现。
  3. 然后经过 GlideContext#buildImageViewTarget()ImageView 封装成 ViewTarget 目标,这儿要注意咱们的 trascodeClassDrawable,它表明 ViewTarget 终究能够处理烘托的目标格式,然后持续调用 into() 办法。

咱们去看看 GlideContext#buildImageViewTarget() 办法是怎样构建 ViewTarget 的:

  @NonNull
  public <X> ViewTarget<ImageView, X> buildImageViewTarget(
      @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
  }

持续调用 ImageViewTargetFactory#buildTarget() 办法:

  @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)) {
      return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
    } else {
      throw new IllegalArgumentException(
          "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
  }

它所支撑的 transcodeClass 只能是 Bitmap 或许 Drawable,咱们的 demo 中是 Drawable,终究的 ViewTarget 完结类是 DrawableImageViewTarget()

在看完了 ViewTarget 创立后,咱们持续咱们的主流程,持续看 into() 办法:

  private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> options,
      Executor callbackExecutor) {
    Preconditions.checkNotNull(target);
    // 假如没有这是 model,直接报错。
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }
    // 构建 Request
    Request request = buildRequest(target, targetListener, options, callbackExecutor);
    // 获取前次的 Request
    Request previous = target.getRequest();
    // 假如前次的 Request 和 当时的恳求共同,直接开端前次的恳求
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        previous.begin();
      }
      return target;
    }
    // 铲除 Target 中前次的恳求。
    requestManager.clear(target);
    // 将当时的 Request 设置到 Target 中。
    target.setRequest(request);
    // 将 target 和 request 告诉 RequestManager
    requestManager.track(target, request);
    return target;
  }

简略阐明下上面的代码:

  1. 检查是否有设置 model,假如没有就直接报错,咱们设置的恳求 url 便是 model
  2. 经过 buildRequest() 构建 Request(后边要点剖析这个办法)。
  3. 判别 ViewTarget 中前次的 Request 和当时的 Request 是否共同,假如共同,就直接回来当时办法(回来之前会判别一下前次的 Request 的运行状况,假如没有运行调用对应的 begin() 办法)。
  4. 经过 RequestManager#clear() 办法铲除 Target 中的 Request
  5. 经过 Target#setRequest() 办法将当时 Request 增加到 Target 中。
  6. TargetRequest 告诉 RequestManager

咱们简略看看 ViewTarget#setRequest() 办法是怎样设置 Request 的:

  @Override
  public void setRequest(@Nullable Request request) {
    setTag(request);
  }
  private void setTag(@Nullable Object tag) {
    isTagUsedAtLeastOnce = true;
    view.setTag(tagId, tag);
  }

Request 其实便是被增加到 Viewtag 上,对应的 tagIdR.id.glide_custom_view_target_tag

咱们再看看 RequestManager#track() 办法是怎样处理 TargetRequest 的:

  synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }

这儿 target 交由 TargetTracker 处理;request 交由 RequestTracker 来处理。

public void track(@NonNull Target<?> target) {
   targets.add(target);  
}

TargetTracker 处理十分简略,直接增加到列表中。

再看看 RequestTracker#runRequest() 办法:

  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");
      }
      pendingRequests.add(request);
    }
  }

request 增加到 requests 列表中,假如当时没有暂停(也便是 onStart() 生命周期)调用 Request#begin() 办法;假如当时已经被暂停,会调用 Request#clear() 办法,然后增加到 pendingRequests 列表中。

咱们持续看看 RequestBuilder#into() 办法中调用过的 buildeRequest() 办法(期望你还没有忘掉),看看它是怎样构建 Request 的。

  private Request buildRequest(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> requestOptions,
      Executor callbackExecutor) {
    return buildRequestRecursive(
        /* requestLock= */ new Object(),
        target,
        targetListener,
        /* parentCoordinator= */ null,
        transitionOptions,
        requestOptions.getPriority(),
        requestOptions.getOverrideWidth(),
        requestOptions.getOverrideHeight(),
        requestOptions,
        callbackExecutor);
  }

持续看 buildRequestRecursive() 办法的完结:

  private Request buildRequestRecursive(
      Object requestLock,
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      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,构建一个 ErrorRequestCoordinator,一起它作为 parentCoordinator
    if (errorBuilder != null) {
      errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }
    // 构建 MainRequest
    Request mainRequest =
        buildThumbnailRequestRecursive(
            requestLock,
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions,
            callbackExecutor);
    if (errorRequestCoordinator == null) {
      // 假如没有对 Error 的处理,直接回来 mainRequest
      return mainRequest;
    }
    int errorOverrideWidth = errorBuilder.getOverrideWidth();
    int errorOverrideHeight = errorBuilder.getOverrideHeight();
    if (Util.isValidDimensions(overrideWidth, overrideHeight) && !errorBuilder.isValidOverride()) {
      errorOverrideWidth = requestOptions.getOverrideWidth();
      errorOverrideHeight = requestOptions.getOverrideHeight();
    }
    // 经过 errorBuilder 构建 errorRequest。
    Request errorRequest =
        errorBuilder.buildRequestRecursive(
            requestLock,
            target,
            targetListener,
            errorRequestCoordinator,
            errorBuilder.transitionOptions,
            errorBuilder.getPriority(),
            errorOverrideWidth,
            errorOverrideHeight,
            errorBuilder,
            callbackExecutor);
    // 将 mainRequest 和 errorRequest 增加到 ErrorRequestCoordinator 中        
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }

简略阐明下上面的办法:

  1. 假如有 errorBuilder,构建一个 ErrorRequestCoordinator,一起它也是后续恳求的 parent
  2. 经过 buildThumbnailRequestRecursive() 构建 mainRequest。假如没有 errorBuilder,直接把 mainRequest 作为成果回来办法。
  3. 经过 errorBuilder 构建 errorRequest
  4. mainRequesterrorRequest 增加到 ErrorRequestCoordinator 中,然后把它作为成果回来。

咱们持续看看 buildThumbnailRequestRecursive() 办法是怎样 mainRequest 的。

  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) {
    // 判别是否有 thumbnailBuilder  
    if (thumbnailBuilder != null) {
      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;
      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 目标
      ThumbnailRequestCoordinator coordinator =
          new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
      // 构建 fullRequest,这其实便是咱们的主恳求    
      Request fullRequest =
          obtainRequest(
              requestLock,
              target,
              targetListener,
              requestOptions,
              coordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overrideHeight,
              callbackExecutor);
      isThumbnailBuilt = true;
      // 构建 thumbRequest。
      Request thumbRequest =
          thumbnailBuilder.buildRequestRecursive(
              requestLock,
              target,
              targetListener,
              coordinator,
              thumbTransitionOptions,
              thumbPriority,
              thumbOverrideWidth,
              thumbOverrideHeight,
              thumbnailBuilder,
              callbackExecutor);
      isThumbnailBuilt = false;
      // 将 fullRequest 和 thumbRequest 增加到 ThumbnailRequestCoordinator 中
      coordinator.setRequests(fullRequest, thumbRequest);
      return coordinator;
    } else if (thumbSizeMultiplier != null) {
      // ...
      return coordinator;
    } else {
      // 没有 thumbnailBuilder,直接构建一个 SingleRequest
      return obtainRequest(
          requestLock,
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight,
          callbackExecutor);
    }
  }
  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);
  }

上面的代码看似许多,其实十分简略:

  1. 判别是否有 thumbnailBuilder (也便是缩略图),假如没有,直接构建一个 SingleRequest 回来,真实的恳求完结都是 SingleRequest 兑现。
  2. 构建一个 ThumbnailRequestCoordinator 目标,它会作为后续恳求的 parent
  3. 构建主恳求 fullRequest 和缩略图恳求 thumbRequest,并把他们增加到 ThumbnailRequestCoordinator 中,然后将它作为成果回来。

所以到这儿咱们能够做一个恳求构建的总结了,咱们以最杂乱的状况为比如来阐明,也便是一起有 ErrorRequestThumbnailReqeust 的恳求:

首先构建一个 ErrorRequestCoordinator,然后经过 errorRequestBuilder 构建一个 errorRequest,持续构建一个 thumbnailRequest。他们都会被增加到 ErrorRequestCoordinator 中,他们的 parent 也都是 ErrorRequestCoordinator
构建 thumnailRequest 时,先创立一个 ThumbnailRequestCoordinator,然后构建一个 fullRequest,也便是主恳求,然后构建一个 thumbnailRequest,也便是缩略图恳求。他们也都被增加到 ThumbnailRequestCoordinator 中,parent 也都是它。

ErrorRequestCoordinator

咱们先简略看看 ErrorRequestCoordinator#begin() 办法的完结:

  @Override
  public void begin() {
    synchronized (requestLock) {
      if (primaryState != RequestState.RUNNING) {
        primaryState = RequestState.RUNNING;
        primary.begin();
      }
    }
  }

直接触发主恳求的 Request#begin()

咱们持续看看 ErrorRequestCoordinator#onRequestFailed() 办法中是怎样处理失利恳求的:

  @Override
  public void onRequestFailed(Request request) {
    synchronized (requestLock) {
      // 假如当时失利的恳求不是 errorRequest,也便是表明主恳求失利了
      if (!request.equals(error)) {
        // 触发 error#begin() 办法
        primaryState = RequestState.FAILED;
        if (errorState != RequestState.RUNNING) {
          errorState = RequestState.RUNNING;
          error.begin();
        }
        return;
      }
      // 以下的状况表明主恳求和失利恳求都失利了
      errorState = RequestState.FAILED;
      if (parent != null) {
        // 告诉 parent 恳求失利了
        parent.onRequestFailed(this);
      }
    }
  }

假如主恳求失利,就会触发 error 恳求开端;假如主恳求和过错的恳求都失利,就表明当时恳求失利了,然后它会告诉 parent

ThumbnailRequestCoordinator

  @Override
  public void begin() {
    synchronized (requestLock) {
      isRunningDuringBegin = true;
      try {
        // 假如 full 恳求没有完结,一起 thumb 也没有在恳求中,触发 thumb 恳求。
        if (fullState != RequestState.SUCCESS && thumbState != RequestState.RUNNING) {
          thumbState = RequestState.RUNNING;
          thumb.begin();
        }
        // 假如 full 没有在恳求中,触发 full 的恳求。
        if (isRunningDuringBegin && fullState != RequestState.RUNNING) {
          fullState = RequestState.RUNNING;
          full.begin();
        }
      } finally {
        isRunningDuringBegin = false;
      }
    }
  }

假如 full 恳求没有完结,一起 thumb 也没有在恳求中,触发 thumb 恳求;假如 full 没有在恳求中,触发 full 的恳求。也便是它会一起触发 fullthumb 的恳求。

咱们持续看看 onRequestSuccess() 办法是怎样处理恳求成功的使命的:

  @Override
  public void onRequestSuccess(Request request) {
    synchronized (requestLock) {
      if (request.equals(thumb)) {
        thumbState = RequestState.SUCCESS;
        return;
      }
      fullState = RequestState.SUCCESS;
      if (parent != null) {
        parent.onRequestSuccess(this);
      }
      if (!thumbState.isComplete()) {
        thumb.clear();
      }
    }
  }

假如是 thumb 恳求成功,仅仅简略更新状况,然后回来;假如是 full 恳求成功,会告诉 parent,然后把 thumb 的恳求取消掉。

咱们再看看它是怎样处理恳求失利的使命的:

  @Override
  public void onRequestFailed(Request request) {
    synchronized (requestLock) {
      if (!request.equals(full)) {
        thumbState = RequestState.FAILED;
        return;
      }
      fullState = RequestState.FAILED;
      if (parent != null) {
        parent.onRequestFailed(this);
      }
    }
  }

也是朴实无华的代码,当 thumb 恳求失利了,也是简略更新状况;full 恳求失利了,更新
状况,一起告诉 parent

简略介绍 Registry

Registry 中注册了许多的重要的功用组件,它是经过 RegistryFactory 来创立实例和初始化的:

  @Synthetic
  static Registry createAndInitRegistry(
      Glide glide,
      List<GlideModule> manifestModules,
      @Nullable AppGlideModule annotationGeneratedModule) {
    BitmapPool bitmapPool = glide.getBitmapPool();
    ArrayPool arrayPool = glide.getArrayPool();
    Context context = glide.getGlideContext().getApplicationContext();
    GlideExperiments experiments = glide.getGlideContext().getExperiments();
    Registry registry = new Registry();
    // 注册默许的体系组件
    initializeDefaults(context, registry, bitmapPool, arrayPool, experiments);
    // 注册自定义的组件,或许替换默许的体系组件
    initializeModules(context, glide, registry, manifestModules, annotationGeneratedModule);
    return registry;
  }

经过 initializeDefaults() 来注册体系组件,等咱们后续需求时再来检查这个办法;经过 initializeModules() 来增加默许的组件,咱们先来看看它的完结:

  private static void initializeModules(
      Context context,
      Glide glide,
      Registry registry,
      List<GlideModule> manifestModules,
      @Nullable AppGlideModule annotationGeneratedModule) {
    for (GlideModule module : manifestModules) {
      try {
        module.registerComponents(context, glide, registry);
      } catch (AbstractMethodError e) {
        throw new IllegalStateException(
            "Attempting to register a Glide v3 module. If you see this, you or one of your"
                + " dependencies may be including Glide v3 even though you're using Glide v4."
                + " You'll need to find and remove (or update) the offending dependency."
                + " The v3 module name is: "
                + module.getClass().getName(),
            e);
      }
    }
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.registerComponents(context, glide, registry);
    }
  }

不知道你是否还记得咱们是怎样把本来的网络恳求替换成 OkHttp 的?便是要经过上面办法触发咱们自定义的 AppGlideModuleregisterComponents() 办法,经过这个办法咱们就能够替换原有的网络恳求为 OkHttp

看到这儿你或许还是不太清楚 Registry 中详细注册了什么样功用的组件。我这儿以一次简略的网络恳求使命来描绘一下其间会用到哪些组件:

首先咱们输入的 url 是一个 String 目标,在 Glide 内部中被称为 model (它也能够是 File 类型,Drawable 类型等等),首先就需求 ModelLoader 来转换处理 model。所以 ModelLoader 就有一个输入类型和输出类型,首先要找到一个 ModelLoaderString 类型的 model 转换成 Url;然后持续找到一个 ModelLoaderUrl 类型的 model 转换成 GlideUrl;终究找到将 GlideUrl 转换成 InputStream 类型的 ModelLoader,没错这个 ModelLoader 其实也便是履行的网络恳求,它也是处理的终究一个 ModelLoader,终究的处理成果就需求交由下一站的组件来处理。
这也是为什么替换原有的网络恳求为 OkHttp,的代码是下面这样:

    override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
        super.registerComponents(context, glide, registry)
        registry.replace(
            GlideUrl::class.java,
            InputStream::class.java,
            OkHttpUrlLoader.Factory(appOkHttpClient)
        )
    }

ModelLoader 处理的下一站便是 Decoder,咱们的 ModelLoader 的输出类型是 InputStream,咱们就需求找到一个 Decoder 支撑的输入类型是 InputStream的,把 InputStream 解码成 Bitmap
在到下一站便是 Transcoder,同样的它也是有一个输入类型和输出类型,Decoder 传过来的类型是 Bitmap,咱们需求将它处理成 ViewTarget 需求的 Drawable 类型,然后 ImageView 就能够直接烘托 Drawable 了。

我仅仅简略介绍了 Registry 中的 ModelLoaderDecoderTranscoder 组件,他们是十分中心的组件。其间还有一些别的组件,比如在缓存到文件时就需求将 Bitmap 从头编码,这时就需求 Encoder

终究

本篇文件介绍了 ReqeustRequestCoordinator,还简略介绍了 Registry 中的中心组件(但是没有看源码)。由于本篇文章的篇幅也不短了,为了不像榜首篇文章那样过长,所以后续的文章持续讲 SingleRequest 中是怎样履行恳求的。