Glide源码分析二

RequestManager 的 load 源码分析

以下分析的所有源码,都只是部分源码,只为了总体流程分析。

Glide 显示网络图片最简单的代码如下:

Glide.with(this).load(url).into(mImageView);

Glide 的加载流程可以概括为以下流程:

model(数据源)-->data(转换数据)-->decode(解码)-->transformed(缩放)-->transcoded(转码)-->encoded(编码保存到本地)

我们知道 with 方法会返回 requestManager 对象,接下来,我们一步步分析 load 的源码。

public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
  return asDrawable().load(bitmap);
}

public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
  return asDrawable().load(drawable);
}

public RequestBuilder<Drawable> load(@Nullable String string) {
  return asDrawable().load(string);
}

public RequestBuilder<Drawable> asDrawable() {
  return as(Drawable.class);
}

public <ResourceType> RequestBuilder<ResourceType> as(
    @NonNull Class<ResourceType> resourceClass) {
    // resourceClass 就是最终要转码的类型
  return new RequestBuilder<>(glide, this, resourceClass, context);
}

load 方法有大量的重载实现,以上源码只展示了部分方法,由上述源码可知,最终调用的是 RequestBuilderload 方法,这个方法也相应有大量的重载方法,下面只展示通过网络地址来加载图片的逻辑。

public RequestBuilder<TranscodeType> load(@Nullable String string) {
  return loadGeneric(string);
}

private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    // 并没有马上进入数据请求加载过程,而是简单的将数据进行了保存,并将isModelSet设置为true
  this.model = model;
  isModelSet = true;
  return this;
}

RequestBuilder 的 into 源码分析

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
  Util.assertMainThread();
  Preconditions.checkNotNull(view);

  BaseRequestOptions<?> requestOptions = this;
  if (!requestOptions.isTransformationSet()
      && requestOptions.isTransformationAllowed()
      && view.getScaleType() != null) {
    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(
      // 将会生成 DrawableImageViewTarget
      glideContext.buildImageViewTarget(view, transcodeClass),
      /*targetListener=*/ null,
      requestOptions,
      Executors.mainThreadExecutor());
}

首先,会根据 ImageView 设置的缩放类型,配置一个请求参数,该参数会在缩放步骤使用到,重点在于最后的方法,第一个参数 glideContext.buildImageViewTarget(view, transcodeClass) 会根据转码的类型来生成一个 ViewTarget,最终会调用如下方法:

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

由于这里的类型是 Drawable,所以最终返回一个 DrawableImageViewTarget 对象。我们接着看 into 方法:

private <Y extends Target<TranscodeType>> Y into(
    @NonNull Y target,
    @Nullable RequestListener<TranscodeType> targetListener,
    BaseRequestOptions<?> options,
    Executor callbackExecutor) {
  Preconditions.checkNotNull(target);
  // 第一步
  // 通过isModelSet检查是否通过load设置了数据源,否则抛出异常
  if (!isModelSet) {
    throw new IllegalArgumentException("You must call #load() before calling #into()");
  }
  // 第二步
  // 创建请求,Request类是一个接口,他抽象了Glide加载图片请求
  Request request = buildRequest(target, targetListener, options, callbackExecutor);

  Request previous = target.getRequest();
  // 第三步
  // 3. 判断当前请求是否已经存在
  if (request.isEquivalentTo(previous)
      && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      //如果是,回收之前创建的 Request
    if (!Preconditions.checkNotNull(previous).isRunning()) {
      // 直接请求
      previous.begin();
    }
    return target;
  }
  // 第四步
  // 清除target
  requestManager.clear(target);
  // 将 SingleRequest 对象保存到ViewTarget的Tag中,所以我们的 ImageView 不能再直接调用 setTaget 方法了。
  // 如果我们确实需要缓存数据,那么只能调用setTag(int key, Object tag)给tag设置一个key
  target.setRequest(request);
  // 调用 track 方法开始请求
  requestManager.track(target, request);

  return target;
}

具体步骤在注释有说明,现在看一下第二步是怎样构建请求的:

// 递归构建请求
  private Request buildRequestRecursive(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      BaseRequestOptions<?> requestOptions,
      Executor callbackExecutor) {

    ErrorRequestCoordinator errorRequestCoordinator = null;
    // 如果设置了请求出错时的备用请求
    if (errorBuilder != null) {
        // 创建错误请求协调器
      errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }

    // 构造目标请求
    Request mainRequest =
        buildThumbnailRequestRecursive(
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions,
            callbackExecutor);

    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(
            target,
            targetListener,
            errorRequestCoordinator,
            errorBuilder.transitionOptions,
            errorBuilder.getPriority(),
            errorOverrideWidth,
            errorOverrideHeight,
            errorBuilder,
            callbackExecutor);
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }

  private Request buildThumbnailRequestRecursive(
      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) {
      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
      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 coordinator = new ThumbnailRequestCoordinator(parentCoordinator);

      // 目标请求
      Request fullRequest =
          obtainRequest(
              target,
              targetListener,
              requestOptions,
              coordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overrideHeight,
              callbackExecutor);
      isThumbnailBuilt = true;
      // Recursively generate thumbnail requests.

      // 缩略图的请求 
      Request thumbRequest =
          thumbnailBuilder.buildRequestRecursive(
              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(parentCoordinator);
      Request fullRequest =
          obtainRequest(
              target,
              targetListener,
              requestOptions,
              coordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overrideHeight,
              callbackExecutor);
      BaseRequestOptions<?> thumbnailOptions =
          requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);

      Request thumbnailRequest =
          obtainRequest(
              target,
              targetListener,
              thumbnailOptions,
              coordinator,
              transitionOptions,
              getThumbnailPriority(priority),
              overrideWidth,
              overrideHeight,
              callbackExecutor);

      coordinator.setRequests(fullRequest, thumbnailRequest);
      return coordinator;
    } else {
      // Base case: no thumbnail.
      // 没有缩略图时,构造请求
      return obtainRequest(
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight,
          callbackExecutor);
    }
  }

构建请求的方法是递归方法,会视情况递归地构建多个请求,为什么会有多个请求呢?因为 Glide 允许你设置请求目标请求失败时的备用请求和缩略图请求,具体描述如下:

  • 错误图片请求(正常的请求出错时,如果有配置该请求,则启动该请求)
  • 缩略图请求(小图请求,可以较快显示。如有配置,在请求开始时,就会启动)
  • 目标图片请求(目标图片请求,在请求开始时,就是启动)

如果除了目标图片外,用户还配置了错误图片显示,或缩略图显示,那么,这时候会创建一个请求协调器,来协调各类型图片间的请求顺序。为了简化流程,我们这里只看目标请求,即没有设置请求目标请求失败时的备用请求和缩略图请求的情况,最终会调用如下方法来构建请求对象。

public static <R> SingleRequest<R> obtain(
    Context context,
    GlideContext glideContext,
    Object model,
    Class<R> transcodeClass,
    BaseRequestOptions<?> requestOptions,
    int overrideWidth,
    int overrideHeight,
    Priority priority,
    Target<R> target,
    RequestListener<R> targetListener,
    @Nullable List<RequestListener<R>> requestListeners,
    RequestCoordinator requestCoordinator,
    Engine engine,
    TransitionFactory<? super R> animationFactory,
    Executor callbackExecutor) {
  @SuppressWarnings("unchecked")
  SingleRequest<R> request = (SingleRequest<R>) POOL.acquire();
  if (request == null) {
  // 创建了一个 SingleRequest 对象
    request = new SingleRequest<>();
  }
  // 初始化赋值,注意赋值参数
  request.init(
      context,
      glideContext,
      model,
      transcodeClass,
      requestOptions,
      overrideWidth,
      overrideHeight,
      priority,
      target,
      targetListener,
      requestListeners,
      requestCoordinator,
      engine,
      animationFactory,
      callbackExecutor);
  return request;
}

到此,into 方法第二步构建请求对象分析完成,我们接着分析第四步,调用了 RequestManager 对象的 track 方法:

// RequestManager.java
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
  targetTracker.track(target);
  // 开始请求
  requestTracker.runRequest(request);
}

接着调用 RequestTrackerrunRequest 方法:

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

至此,通过 SingleRequestbegin 方法来开始加载请求任务:

public synchronized void begin() {
  assertNotCallingCallbacks();
  stateVerifier.throwIfRecycled();
  startTime = LogTime.getLogTime();
  // model 为空
  if (model == null) {
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      width = overrideWidth;
      height = overrideHeight;
    }
    // 加载错误的处理
    onLoadFailed(new GlideException("Received null model"), logLevel);
    return;
  }

  if (status == Status.RUNNING) {
    throw new IllegalArgumentException("Cannot restart a running request");
  }

  if (status == Status.COMPLETE) {
      // 请求加载完成后会回调
    onResourceReady(resource, DataSource.MEMORY_CACHE);
    return;
  }

  status = Status.WAITING_FOR_SIZE;
  if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      // 如果图片显示尺寸有效,直接回调 onSizeReady
    onSizeReady(overrideWidth, overrideHeight);
  } else {
      // 根据 target 的宽高来加载图片的宽高
    target.getSize(this);
  }

  if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
      && canNotifyStatusChanged()) {
      // 开始请求,显示加载占位图
    target.onLoadStarted(getPlaceholderDrawable());
  }
}

如果 model 为空,也就是我们传入的图片地址为空,则会调用 onLoadFailed 方法,在该方法会先回调监听器的失败回调,然后又调用了 setErrorPlaceholder 方法,接着看看该方法中做了什么操作。

private synchronized void setErrorPlaceholder() {
  if (!canNotifyStatusChanged()) {
    return;
  }

  Drawable error = null;
  // 传入的地址为空
  if (model == null) {
      // 获取 fallback 资源
    error = getFallbackDrawable();
  }

  // 如果没有设置 fallback 资源
  if (error == null) {
      // 获取 error 资源
    error = getErrorDrawable();
  }

  // 如果没有设置 error 资源
  if (error == null) {
      // 获取 placeholder 资源
    error = getPlaceholderDrawable();
  }
  target.onLoadFailed(error);
}

如果我们传入图片地址为空,则首先查看是否有后备回调符设置,然后是错误占位符,最后是加载占位符,最终调用 target.onLoadFailed 方法,也就是 ImageViewTargetonLoadFailed 方法。

public void onLoadFailed(@Nullable Drawable errorDrawable) {
  super.onLoadFailed(errorDrawable);
  setResourceInternal(null);
  // 加载失败后设置的 Drawable
  setDrawable(errorDrawable);
}

begin 方法里还有 target.onLoadStarted(getPlaceholderDrawable()) 代码用来正常显示加载任务时的占位符。当获取到有效的图片尺寸后,会回调 onSizeReady() 方法。

public synchronized void onSizeReady(int width, int height) {
  stateVerifier.throwIfRecycled();
  if (status != Status.WAITING_FOR_SIZE) {
    return;
  }
  status = Status.RUNNING;

  float sizeMultiplier = requestOptions.getSizeMultiplier();
  this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
  this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

  loadStatus =
      // 加载图片并返回状态
      // engine 对象的在实例化 Glide 对象时由 GlideBuilder 创建的 (GlideBuilder创建了所有的默认配置选项)
      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);

  if (status != Status.RUNNING) {
    loadStatus = null;
  }
}

上述方法,调用了 engineload 方法来加载请求任务。

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,
    Executor callbackExecutor) {
  long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

  // 创建资源索引 KEY
  EngineKey key =
      keyFactory.buildKey(
          model,
          signature,
          width,
          height,
          transformations,
          resourceClass,
          transcodeClass,
          options);

  EngineResource<?> memoryResource;
  synchronized (this) {
      // 如果可以从内存缓存中获取,则先获取内存缓存的
    memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
      // 内存缓存的数据为空
    if (memoryResource == null) {
      return waitForExistingOrStartNewJob(
          glideContext,
          model,
          signature,
          width,
          height,
          resourceClass,
          transcodeClass,
          priority,
          diskCacheStrategy,
          transformations,
          isTransformationRequired,
          isScaleOnlyOrNoTransform,
          options,
          isMemoryCacheable,
          useUnlimitedSourceExecutorPool,
          useAnimationPool,
          onlyRetrieveFromCache,
          cb,
          callbackExecutor,
          key,
          startTime);
    }
  }

  // 直接拿内存缓存的数据并回调加载完成,传入的类型为 MEMORY_CACHE
  cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
  return null;
}

上述方法先根据 KEY 来获取内存缓存数据,如果内存,则直接回调成功,如果不存在,则调用 waitForExistingOrStartNewJob 方法做进一步处理。

先来看一下从内存缓存中取数据的代码:

private EngineResource<?> loadFromMemory(
    EngineKey key, boolean isMemoryCacheable, long startTime) {
  if (!isMemoryCacheable) {
    return null;
  }
  // 从内存中当前正在显示的资源缓存加载图片
  EngineResource<?> active = loadFromActiveResources(key);
  if (active != null) {
    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Loaded resource from active resources", startTime, key);
    }
    return active;
  }
  // 从内存缓存资源中加载图片
  EngineResource<?> cached = loadFromCache(key);
  if (cached != null) {
    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Loaded resource from cache", startTime, key);
    }
    return cached;
  }

  return null;
}

如果要加载的图片已经正在显示,直接使用已有的资源。如果图片没有在显示,但是已经正好还在内存缓存中,没有被销毁,那么直接使用缓存中的资源。

我们再看 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) {

  // 获取已经存在的加载任务 ,onlyRetrieveFromCache 参数表示是否只加载缓存中的数据
  EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
  if (current != null) {
      // 添加 SingleRequest 回调对象 
    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 对象,是一个 Runnable 对象,真正执行数据加载和解码的类
  DecodeJob<R> decodeJob =
  // 将EngineJob传入,用于回调
      decodeJobFactory.build(
          glideContext,
          model,
          key,
          signature,
          width,
          height,
          resourceClass,
          transcodeClass,
          priority,
          diskCacheStrategy,
          transformations,
          isTransformationRequired,
          isScaleOnlyOrNoTransform,
          onlyRetrieveFromCache,
          options,
          engineJob);

  // 缓存加载任务
  jobs.put(key, engineJob);

  // 添加 SingleRequest 回调对象 
  engineJob.addCallback(cb, callbackExecutor);
  // 执行解码任务
  engineJob.start(decodeJob);

  if (VERBOSE_IS_LOGGABLE) {
    logWithTimeAndKey("Started new load", startTime, key);
  }
  return new LoadStatus(cb, engineJob);
}

上述方法最终会调用 engineJobstart 方法从网络或者本地硬盘中去加载一张图片。

public synchronized void start(DecodeJob<R> decodeJob) {
  this.decodeJob = decodeJob;
  // GlideExecutor就是一个线程池执行器(Executor),有各种方法获得缓存线程池,还有资源线程池(SourceExecutor)
  // start 方法就是用来在线程池中启动DecodeJob这个Runnable对象,
  // 也就是说EngineJob的主要作用是开启线程来加载图片
  GlideExecutor executor =
      decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
  executor.execute(decodeJob);
}

DecodeJob 是一个继承 Runnable 的类,任务启动的入口就在run方法中,最终会调用 runWrapped 方法。

private void runWrapped() {
  switch (runReason) {
    case INITIALIZE:
      stage = getNextStage(Stage.INITIALIZE);
      currentGenerator = getNextGenerator();
      runGenerators();
      break;
    case SWITCH_TO_SOURCE_SERVICE:
      runGenerators();
      break;
    case DECODE_DATA:
      decodeFromRetrievedData();
      break;
    default:
      throw new IllegalStateException("Unrecognized run reason: " + runReason);
  }
}

然后会调用下面这些方法:

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

private void runGenerators() {
  currentThread = Thread.currentThread();
  startFetchTime = LogTime.getLogTime();
  boolean isStarted = false;
  // 循环调用了 startNext 方法
  while (!isCancelled
      && currentGenerator != null
      && !(isStarted = currentGenerator.startNext())) {
    stage = getNextStage(stage);
    currentGenerator = getNextGenerator();

    if (stage == Stage.SOURCE) {
      reschedule();
      return;
    }
  }

  if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
    notifyFailed();
  }
}

上述的这几个方法构成了 Glide 的解码流程,分为三步:

  1. 尝试从处理过的本地资源加载图片。
  2. 尝试从未处理过的原始本地资源加载图片。
  3. 尝试从远程加载图片。

这是一个嵌套的循环,通过状态的切换来寻找下一个加载器,直到加载一张图片,返回成功;或者找不到要加载的图片,返回失败。我们从最后一个SourceGenerator加载器入手,因为,当你第一次加载一张新的网络图片时,本地并没有这张网络图片的缓存。从runGenerators方法中看到,Generator的入口是startNext()方法:

public boolean startNext() {
    // 1. 判断是否有缓存
  if (dataToCache != null) {
    Object data = dataToCache;
    dataToCache = null;
   // 缓存数据
    cacheData(data);
  }

  if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
    return true;
  }
  sourceCacheGenerator = null;

  // 没有缓存,从远程加载
  loadData = null;
  boolean started = false;
  // 2. 遍历所有的ModelLoader模块加载器
  while (!started && hasNextModelLoader()) {
      // 关键代码 ,拿到 HttpGlideUrlLoader 对象
    loadData = helper.getLoadData().get(loadDataListIndex++);
    if (loadData != null
        && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
            || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
      started = true;
      // 调用 HttpUrlFetcher 的 loadData 方法
      loadData.fetcher.loadData(helper.getPriority(), this);
    }
  }
  return started;
}

我们直接看从远程中加载,其中调用了 DecodeHelper 的 getLoadData() 方法:

//DecodeHelper.java
List<LoadData<?>> getLoadData() {
  if (!isLoadDataSet) {
    isLoadDataSet = true;
    loadData.clear();
      // 获取所有的 ModelLoader 对象
    List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = modelLoaders.size(); i < size; i++) {
      ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
      LoadData<?> current = modelLoader.buildLoadData(model, width, height, options);
      if (current != null) {
        loadData.add(current);
      }
    }
  }
  return loadData;
}

上述代码最终会通过 ModelLoaderRegistry 类的 getModelLoaders 方法获取 model 类型对应的数据转换器ModelLoader。

回到 startNext 方法,最终返回的是 HttpGlideUrlLoader 对象,然后调用 HttpGlideUrlLoader 的 fetcher (HttpUrlFetcher) 的 loadData 方法。

  // HttpUrlFetcher.java
  public void loadData(
      @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    try {
        // 调用自身的 loadDataWithRedirects 方法
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
        // 成功回调
      callback.onDataReady(result);
    } catch (IOException e) {
      // 失败回调
      callback.onLoadFailed(e);
    } finally {
    }
}

上述方法又会调用 loadDataWithRedirects 方法,利用 HttpURLConnection 来获取网络图片的 InputStream 对象。最后通过 callback.onDataReady(result) 将结果回调给 SourceGenerator 进行下一步处理。

// SourceGenerator.java
public void onDataReady(Object data) {
  DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
  if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      // 赋值给一个缓存对象(重点),重启任务的时候会在 startNext再次判断这个对象
    dataToCache = data;
    // We might be being called back on someone else's thread. Before doing anything, we should
    // reschedule to get back onto Glide's thread.
    // 重启 DecodeJob 任务
    cb.reschedule();
  } else {
      // 不处理缓存,回调 DecodeJob 的 onDataFetcherReady 方法
    cb.onDataFetcherReady(
        loadData.sourceKey,
        data,
        loadData.fetcher,
        loadData.fetcher.getDataSource(),
        originalKey);
  }
}

获取到数据后,分两种情况,一是需要将图片缓存到本地硬盘,一种是不需要缓存。Glide配置了多种缓存策略,默认是自动智能切换缓存存储策略,Glide认为远程网络图片获取是昂贵的,所以默认网络图片是会缓存原图的。而本地图片,包括drawable/assets等是不会缓存原图的。(当然你也可以重新配置)

进入if后,会将数据保存起来(留意dataToCache),然后重启任务。

//DecodeJob.java
@Override
public void reschedule() {
  runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
  callback.reschedule(this);
}

//EngineJob.java
@Override
public void reschedule(DecodeJob<?> job) {
  getActiveSourceExecutor().execute(job);
}

最终又会回到 SourceGenerator 的 startNext 方法中。

public boolean startNext() {

    // 1. 判断是否有缓存
  if (dataToCache != null) {
    Object data = dataToCache;
    dataToCache = null;
   // 缓存数据
    cacheData(data);
  }
   // 省略代码...
}

此时 dataToCache 将不再是 null 的,所以会将数据缓存到本地硬盘,并启动另一个加载器DataCacheGenerator,而这个Generator正是用来加载缓存在本地的图片的。

而DataCacheGenerator和ResourceCacheGenerator的原理与SourceGenerator基本是一致的,只不过一个用来加载原始的本地缓存图,另一个用来加载处理过的本地缓存。最终还是会回调 DecodeJob 的 onDataFetcherReady 方法。

public void onDataFetcherReady(
    Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
  this.currentSourceKey = sourceKey;
  // 将请求返回的 InputStream 流赋值给 currentData
  this.currentData = data;
  this.currentFetcher = fetcher;
  this.currentDataSource = dataSource;
  this.currentAttemptingKey = attemptedKey;
  if (Thread.currentThread() != currentThread) {
    runReason = RunReason.DECODE_DATA;
    callback.reschedule(this);
  } else {
    GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
    try {
        // 关键代码,解码数据
      decodeFromRetrievedData();
    } finally {
      GlideTrace.endSection();
    }
  }
}

至此,整个数据模型转换和数据抓取流程分析完毕,下面来总结一下:

  1. Glide利用线程池的方式,将每一个解码过程都封装为一次解码任务。
  2. 整个数据抓取过程中,Glide会尝试从内存到处理过的图片缓存,再到原图缓存,最后到远程图片等四个地方进行数据加载。(这里的远程图片包括drawable/assets等资源)
  3. 数据模型转换时,根据Glide初始化时注册的模型转换注册表,将原始model模型数据转换为可能的数据模型,并尝试使用这些模型来抓取数据,直至抓取到数据,或抓取失败返回。