Glide v4 源码浅析(3)-into(上)


简述

Glide图片加载框架通过into方法为视图设置图片,在《Glide v4 源码浅析(2)-load方法与Registry说明》中通过load方法获得了一个RequestBuilder对象,这里将调用它的into方法传入ImageView,开始加载资源并显示在ImageView上。

into中的执行流程很长,这里分成上下两部分。上部分主要分析拉取源数据的过程,下部分记录对数据进行解码转换处理后设置到ImageView的过程。

源码分析

ViewTarget创建

into方法有多个重载,这里调用的是:

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

  RequestOptions requestOptions = this.requestOptions;
  // 设置缩放属性
  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.
    }
  }

  // 先创建ViewTarget,然后传入into方法
  return into(
      glideContext.buildImageViewTarget(view, transcodeClass),
      /*targetListener=*/ null,
      requestOptions);
}

先看glideContext.buildImageViewTarget方法:

@NonNull
public<X> ViewTarget<ImageView, X> buildImageViewTarget(
    @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
  // imageViewTargetFactory为GlideContext初始化时传入的ImageViewTargetFactory对象。
  return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
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的类型创建对应的ViewTarget子类。本例的transcodeClass为Drawable.class,因此返回DrawableImageViewTarget对象。

ps:ViewTarget是介于请求和请求者之间的中介者的角色,它负责在View上加载展示资源。

回到into方法:

private <Y extends Target<TranscodeType>> Y into(
    @NonNull Y target,
    @Nullable RequestListener<TranscodeType> targetListener,
    @NonNull RequestOptions options) {
  Util.assertMainThread();
  Preconditions.checkNotNull(target);
  // 调用load方法后isModelSet设为true。
  if (!isModelSet) {
    throw new IllegalArgumentException("You must call #load() before calling #into()");
  }

  options = options.autoClone();
  // 创建为target加载资源的请求,实例为SingleRequest。
  Request request = buildRequest(target, targetListener, options);

  // 取出target中保存的上一次的请求。
  Request previous = target.getRequest();
  if (request.isEquivalentTo(previous)
      && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
    // 若当前创建的请求和上一次的请求的参数、配置、优先级、监听器数量等一致,并且,		  
    // 允许内存缓存或者上一次请求未成功完成,则释放本次创建的请求的资源。
    request.recycle();
    // 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.
      // 若上一次请求不在运行中,则启动它开始异步加载。
      previous.begin();
    }
    return target;
  }

  // 通过RequestManager取消target的请求的加载(若有)并释放已为它加载的资源(若有)。
  requestManager.clear(target);
  // 设置请求到target中保存。
  target.setRequest(request);
  // 分别保存target和request在RequestManager的set集合中,并且启动request加载。
  requestManager.track(target, request);

  return target;
}

在该方法中创建了Request,之后判断ViewTarget中是否设置了相同的Request,若存在且不在请求进行中,则启动之前设置的请求。若ViewTarget未设置过相同的Request,则清除ViewTarget中的Request,并将本次的Request设置给ViewTarget,接着启动本次Request。
into方法最终返回ViewTarget,我们可以利用进行它取消或重新加载展示资源等操作,也可以不进行任何处理。

Request创建和开始加载

在into方法中通过buildRequest方法创建了一个Request:

private Request buildRequest(
    Target<TranscodeType> target,
    @Nullable RequestListener<TranscodeType> targetListener,
    RequestOptions requestOptions) {
  return buildRequestRecursive(
      target,
      targetListener,
      /*parentCoordinator=*/ null,
      transitionOptions,
      requestOptions.getPriority(),
      requestOptions.getOverrideWidth(),
      requestOptions.getOverrideHeight(),
      requestOptions);
}

又调用buildRequestRecursive方法:

private Request buildRequestRecursive(
    Target<TranscodeType> target,
    @Nullable RequestListener<TranscodeType> targetListener,
    @Nullable RequestCoordinator parentCoordinator,
    TransitionOptions<?, ? super TranscodeType> transitionOptions,
    Priority priority,
    int overrideWidth,
    int overrideHeight,
    RequestOptions requestOptions) {

  // Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
  ErrorRequestCoordinator errorRequestCoordinator = null;
  // errorBuilder通过error方法设置,默认为空。
  if (errorBuilder != null) {
    errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
    parentCoordinator = errorRequestCoordinator;
  }

  // 创建Request对象
  Request mainRequest =
      buildThumbnailRequestRecursive(
          target,
          targetListener,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight,
          requestOptions);

  // errorRequestCoordinator默认为空,直接返回mainRequest。
  if (errorRequestCoordinator == null) {
    return mainRequest;
  }
  
  // 创建加载错误情况下的二次请求,默认为空,先忽略。
  ···
}

继续看buildThumbnailRequestRecursive方法:

private Request buildThumbnailRequestRecursive(
    Target<TranscodeType> target,
    RequestListener<TranscodeType> targetListener,
    @Nullable RequestCoordinator parentCoordinator,
    TransitionOptions<?, ? super TranscodeType> transitionOptions,
    Priority priority,
    int overrideWidth,
    int overrideHeight,
    RequestOptions requestOptions) {
  if (thumbnailBuilder != null) {
    // thumbnailBuilder通过thumbnail方法设置,默认为空。
    // 创建加载缩略图的递归请求。
    ···
    return coordinator;
  } else if (thumbSizeMultiplier != null) {
    // thumbSizeMultiplier通过thumbnail方法设置,默认为空。
    // 创建加载缩略图的递归请求。
    ···
    return coordinator;
  } else {
    // Base case: no thumbnail.
    // 默认情况下执行到这个case里。
    return obtainRequest(
        target,
        targetListener,
        requestOptions,
        parentCoordinator,
        transitionOptions,
        priority,
        overrideWidth,
        overrideHeight);
  }
}

接着看obtainRequest方法:

private Request obtainRequest(
    Target<TranscodeType> target,
    RequestListener<TranscodeType> targetListener,
    RequestOptions requestOptions,
    RequestCoordinator requestCoordinator,
    TransitionOptions<?, ? super TranscodeType> transitionOptions,
    Priority priority,
    int overrideWidth,
    int overrideHeight) {
  return SingleRequest.obtain(
      context,
      glideContext,
      model,
      transcodeClass,
      requestOptions,
      overrideWidth,
      overrideHeight,
      priority,
      target,
      targetListener,
      requestListeners,
      requestCoordinator,
      glideContext.getEngine(),
      transitionOptions.getTransitionFactory());
}

可以看到创建Request过程最终是返回了SingleRequest实例。 在这个过程中还可以根据用户设置创建递归请求,当一个请求结束时通知下一个请求。

回到into方法中,在获取到Request之后,会通过RequestManager启动Request:

void track(@NonNull Target<?> target, @NonNull Request request) {
  // targetTracker中维护了一个Set集合,用来保存Target,并实现
  // LifecycleListener接口,转发生命周期事件给Set中的Target。
  targetTracker.track(target);
  // requestTracker用于跟踪、取消和重新启动正在进行、已完成和失败的请求。
  requestTracker.runRequest(request);
}

看runRequest方法:

public void runRequest(@NonNull Request request) {
  // 添加至Set集合中保存
  requests.add(request);
  // RequestManager是否暂停或释放所有进行中的请求。
  if (!isPaused) {
    // 开始加载。
    request.begin();
  } else {
  	// 取消加载并释放资源。
    request.clear();
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      Log.v(TAG, "Paused, delaying request");
    }
    // 加入等待队列。
    pendingRequests.add(request);
  }
}

这里调用了SingleRequest的begin方法。接下来才开始真正发起加载请求:

public void begin() {
  assertNotCallingCallbacks();
  stateVerifier.throwIfRecycled();
  startTime = LogTime.getLogTime();
  // 检查load方法传入的数据源是否为空。
  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);
    return;
  }

  // Restarts for requests that are neither complete nor running can be treated as new requests
  // and can run again from the beginning.

  // 状态置为等待确认目标尺寸。
  status = Status.WAITING_FOR_SIZE;
  if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
    // 存在有效宽高,回调尺寸确认成功。默认都为-1,不会直接回调。
    onSizeReady(overrideWidth, overrideHeight);
  } else {
    // 通过target获取有效宽高。
    target.getSize(this);
  }

  if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
      && canNotifyStatusChanged()) {
    // 状态为运行中或等待确认尺寸中时调用target的开始加载回调方法。
    // 该回调方法中会添加OnAttachStateChangeListener监听和将获取设置的占位图填充到view上。
    target.onLoadStarted(getPlaceholderDrawable());
  }
  if (IS_VERBOSE_LOGGABLE) {
    logV("finished run method in " + LogTime.getElapsedMillis(startTime));
  }
}

begin方法中会进行状态校验,根据当前status执行对应的case。
SingleRequest包含以下几个状态:

statusdescription
PENDING已创建但尚未运行
RUNNING运行获取资源中
WAITING_FOR_SIZE等待确认目标尺寸
COMPLETE加载资源成功
FAILED加载资源失败
CLEARED取消加载,或替换占位图加载

这里当首次开始加载图片时,将调用target的getSize方法确认尺寸(本例中target为DrawableImageViewTarget对象)。在target中又使用SizeDeterminer辅助类获取尺寸,其中通过给view注册ViewTreeObserver监听布局绘制,获取LayoutParams和padding来确定尺寸,并且处理了自定义父布局LayoutParams获取不正确时通过view.getWidth()来确定尺寸。若view设置了WRAP_CONTENT,则获取屏幕尺寸最长的长度作为尺寸,避免图片过大OOM。当尺寸确定后就会调用SingleRequest的onSizeReady方法,传入宽和高。

接下来进入onSizeReady方法:

@Override
public void onSizeReady(int width, int height) {
  stateVerifier.throwIfRecycled();
  if (IS_VERBOSE_LOGGABLE) {
    logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
  }
  if (status != Status.WAITING_FOR_SIZE) {
    return;
  }
  // 将状态置为RUNNING。
  status = Status.RUNNING;

  // 将width、height乘以乘数,乘数默认为1f。
  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对象(LoadStatus可用于移除这里传入的ResourceCallback回调,
  // 使之不再监听加载结果)。
  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);

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

SingleRequest在获取到目标尺寸后,即通过Engine开始进行资源加载。

Engine启动
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) {
  Util.assertMainThread();
  long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

  // 利用各个参数构建用于缓存的Key。
  EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
      resourceClass, transcodeClass, options);
  // 从活动的资源缓存中获取EngineResource对象,EngineResource为资源的装饰者对象,它还含有一个引用计数,
  // 此时获取的缓存资源的同时会增加计数。
  EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
  if (active != null) {
    // 回调通知外层资源可用。
    cb.onResourceReady(active, DataSource.MEMORY_CACHE);
    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Loaded resource from active resources", startTime, key);
    }
    return null;
  }

  // 从非活动的资源缓存中获取资源对象,并将其移至活动的资源缓存中,同时增加引用计数。
  EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
  if (cached != null) {
    // 回调通知外层资源可用。
    cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Loaded resource from cache", startTime, key);
    }
    return null;
  }

  // 从任务集合中查找相同key的任务。若存在相同的任务,则复用这个任务,添加回调。
  EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
  if (current != null) {
    // 添加回调时,若任务已获取到资源,则直接回调资源加载成功,若已失败,则直接回调加载失败。
    current.addCallback(cb);
    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,负责解码和转换资源。
  DecodeJob<R> decodeJob =
      decodeJobFactory.build(
          glideContext,
          model,
          key,
          signature,
          width,
          height,
          resourceClass,
          transcodeClass,
          priority,
          diskCacheStrategy,
          transformations,
          isTransformationRequired,
          isScaleOnlyOrNoTransform,
          onlyRetrieveFromCache,
          options,
          engineJob);

  // 保存至任务集合中。
  jobs.put(key, engineJob);

  // 添加资源加载回调。
  engineJob.addCallback(cb);
  // 开始加载。
  engineJob.start(decodeJob);

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

该方法中首先从活动的资源缓存中查找资源,活动的资源即为被引用的资源,比如某个view中在使用的bitmap或drawable。若不存在,接着从非活动的资源缓存中查找,找到后会移至活动资源缓存中,并主动增加该资源的引用计数。若不存在缓存,则判断是否存在相同的任务,有则复用该任务,添加回调等待加载完成。若仍不存在,最终新建任务,启动加载。

该方法中如果没有找到缓存,最后会返回LoadStatus对象,该对象包含EngineJob和ResourceCallback,可用于从EngineJob中移除添加的ResourceCallback。

假设本例中尚未存在缓存,需要从远程加载资源。往下看EngineJob的start方法:

public void start(DecodeJob<R> decodeJob) {
  this.decodeJob = decodeJob;
  // 这里使用diskCacheExecutor线程池启动DecodeJob。
  GlideExecutor executor = decodeJob.willDecodeFromCache()
      ? diskCacheExecutor
      : getActiveSourceExecutor();
  executor.execute(decodeJob);
}

EngineJob中又通过线程池启动了DecodeJob,DecodeJob实现了Runnable接口,在它的run方法又调用了runWrapped方法:

private void runWrapped() {
  // runReason初始值为INITIALIZE。
  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);
  }
}

runWrapped方法中有3个case,分别执行不同的操作:

  • INITIALIZE:初始阶段,需要获取下一个阶段,执行下个阶段对应的操作。
  • SWITCH_TO_SOURCE_SERVICE:需要从磁盘缓存获取数据切换到从数据源获取数据。
  • DECODE_DATA:需要对获取到的数据进行解码转换。

接着看getNextStage方法,该方法返回下一个状态:

private Stage getNextStage(Stage current) {
  // current初始值为INITIALIZE。
  switch (current) {
    case INITIALIZE:
      // 是否尝试从加工过的资源的磁盘缓存中获取,若否则返回下个阶段。本例中diskCacheStrategy为DiskCacheStrategy.AUTOMATIC,返回RESOURCE_CACHE。
      return diskCacheStrategy.decodeCachedResource()
          ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
    case RESOURCE_CACHE:
      // 是否尝试从未加工的资源的磁盘缓存中获取。返回DATA_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.
      // onlyRetrieveFromCache默认为false,这里返回SOURCE。
      return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
    case SOURCE:
    case FINISHED:
      return Stage.FINISHED;
    default:
      throw new IllegalArgumentException("Unrecognized stage: " + current);
  }
}

这里有5个阶段:

  • INITIALIZE:初始阶段。
  • RESOURCE_CACHE:从缓存的资源解码(磁盘缓存的经过采样、转换的加工过的资源)。
  • DATA_CACHE:从缓存的源数据解码(磁盘缓存的未经过加工的原始资源)。
  • SOURCE:从获取到的源数据解码(从传入的数据源model加载的资源)。
  • ENCODE:成功加载后对转换后的资源进行解码。
  • FINISHED:最后阶段,结束。

ps:Engine.load方法中是对内存缓存中的资源进行检索,DecodeJob中是对磁盘缓存中的资源进行检索。磁盘缓存中又分为加工和未加工的资源,未加工即从mode加载来的原始资源,加工即对加载来的资源进行采样、缩放、裁剪等操作的资源。

回到runWrapped方法,在返回stage后,调用getNextGenerator方法:

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

该方法就是根据不同的阶段创建对应的DataFetcherGenerator。

返回DataFetcherGenerator之后就调用runGenerators方法:

private void runGenerators() {
  currentThread = Thread.currentThread();
  startFetchTime = LogTime.getLogTime();
  boolean isStarted = false;
  // 遍历执行currentGenerator.startNext,若成功处理返回true,否则尝试下个阶段
  // 的DataFetcherGenerator。
  while (!isCancelled && currentGenerator != null
      && !(isStarted = currentGenerator.startNext())) {
    // 获取下个阶段和阶段对应的DataFetcherGenerator。
    stage = getNextStage(stage);
    currentGenerator = getNextGenerator();

    if (stage == Stage.SOURCE) {
      // 到了SOURCE阶段,直接执行reschedule方法,不再执行后续代码。
      reschedule();
      return;
    }
  }
  // We've run out of stages and generators, give up.
  // 若到了最后阶段或已取消,且仍没有DataFetcherGenerator成功处理,则通知加载失败。
  if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
    notifyFailed();
  }

  // Otherwise a generator started a new load and we expect to be called back in
  // onDataFetcherReady.
}

假设此时是首次加载图片,无任何缓存,则会执行到SOURCE阶段,直接看reschedule方法:

@Override
public void reschedule() {
  // 将runReason赋值为SWITCH_TO_SOURCE_SERVICE,表示需要从传入model加载数据。
  runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
  // 这里的callback为EngineJob实例,在DecodeJob创建时传入,EngineJob实现了DecodeJob.Callback接口。
  callback.reschedule(this);
}

在callback(即EngineJob实例)的reschedule方法里又通过线程池执行DecodeJob的run方法,这样又回到上面的流程。回到runWrapped方法中,此时的runReason已赋值成SWITCH_TO_SOURCE_SERVICE,在这个case中,直接调用runGenerators方法。在runGenerators方法中依然执行currentGenerator.startNext(此时的currentGenerator已赋值为SourceGenerator实例)。

下面进入SourceGenerator.startNext方法中:

@Override
public boolean startNext() {
  // 源数据是否加载完成,若完成则进行缓存。默认为null。
  if (dataToCache != null) {
    Object data = dataToCache;
    dataToCache = null;
    cacheData(data);
  }

  // 当执行上一步cacheData时,sourceCacheGenerator会被创建用来从缓存中获取数据。默认为null。
  if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
    return true;
  }
  sourceCacheGenerator = null;

  loadData = null;
  boolean started = false;
  // 遍历LoadData,逐个尝试。
  while (!started && hasNextModelLoader()) {
    // 从Registry中查找。
    loadData = helper.getLoadData().get(loadDataListIndex++);
    if (loadData != null
        && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
        || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
      // 找到可用的LoadData,开始拉取源数据。
      started = true;
      loadData.fetcher.loadData(helper.getPriority(), this);
    }
  }
  // 若找到可用的LoadData,将返回true。
  return started;
}

LoadData由ModelLoader生成,它包含一个Source Key和一组备用Key和一个DataFetcher对象。DataFetcher负责真正执行获取数据。

假设第一次加载图片不存在缓存,直接看while循环部分。

hasNextModelLoader方法中判断索引是否超出LoadData列表:

private boolean hasNextModelLoader() {
  return loadDataListIndex < helper.getLoadData().size();
}

接着看helper.getLoadData方法:

List<LoadData<?>> getLoadData() {
  // 是否有缓存,有则直接返回,否则重新查找。
  if (!isLoadDataSet) {
    isLoadDataSet = true;
    loadData.clear();
    // 根据model的类类型从Registry中查找所有对应的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);
      // 由ModelLoader创建LoadData。
      LoadData<?> current =
          modelLoader.buildLoadData(model, width, height, options);
      if (current != null) {
        loadData.add(current);
      }
    }
  }
  return loadData;
}
ModelLoader筛选

获取所有model对应的ModelLoader是从Registry的子表ModelLoaderRegistry中查找:

@NonNull
public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
  // 获取model的类类型,然后获取该类型对应的所有ModelLoader。
  List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
  int size = modelLoaders.size();
  boolean isEmpty = true;
  List<ModelLoader<A, ?>> filteredLoaders = Collections.emptyList();
  //noinspection ForLoopReplaceableByForEach to improve perf
  for (int i = 0; i < size; i++) {
    ModelLoader<A, ?> loader = modelLoaders.get(i);
    // 通过ModelLoader的handles判断是否支持处理该model(每个ModelLoader实现不一样)。
    if (loader.handles(model)) {
      if (isEmpty) {
        filteredLoaders = new ArrayList<>(size - i);
        isEmpty = false;
      }
      // 保存进集合。
      filteredLoaders.add(loader);
    }
  }
  // 返回筛选后的ModelLoader列表。
  return filteredLoaders;
}

在Glide初始化的时候,Registry注册了一些列的ModelLoaderFactory,详细见ModelLoader映射表。在getModelLoadersForClass方法中会依次遍历这些ModelLoaderFactory,若注册时设置的model类型是当前传入的model类型的超类,则调用build方法构建ModelLoader。

例如本例从url加载图片,传入的model类型为String.class,则匹配的ModelLoaderFactory有DataUrlLoader.StreamFactory、StringLoader.StreamFactory、StringLoader.FileDescriptorFactory、StringLoader.AssetFileDescriptorFactory。

获取到ModelLoader列表后,再进一步对其进行筛选,这里依次看DataUrlLoader和StringLoader的handles方法:

/** DataUrlLoader */
@Override
public boolean handles(@NonNull Model model) {
  // We expect Model to be a Uri or a String, both of which implement toString() efficiently. We
  // should reconsider this implementation before adding any new Model types.
  // 本例中的model为"http"开头,而DATA_SCHEME_IMAGE为"data:image",因此不匹配。
  return model.toString().startsWith(DATA_SCHEME_IMAGE);
}
/** StringLoader */
@Override
public boolean handles(@NonNull String model) {
  // Avoid parsing the Uri twice and simply return null from buildLoadData if we don't handle this
  // particular Uri type.
  return true;
}

经过筛选后,getModelLoaders方法最终返回的ModelLoader列表仅包含3个StringLoader实例。

回到DecodeHelper的getLoadData方法,在for循环中依次调用ModelLoader的buildLoadData方法创建LoadData。看StringLoader:

@Override
public LoadData<Data> buildLoadData(@NonNull String model, int width, int height,
    @NonNull Options options) {
  Uri uri = parseUri(model);
  // 在StringLoader中又包含ModelLoader的成员变量,这里实际是调用了这个ModelLoader,
  // 相当于代理模式。
  if (uri == null || !uriLoader.handles(uri)) {
    return null;
  }
  return uriLoader.buildLoadData(uri, width, height, options);
}

StringLoader中的uriLoader是在构造函数中被赋值,可以查看StringLoader中的3个工厂类的build方法,创建了MultiModelLoader类型的ModelLoader,其中又包含了多个ModelLoader,同样是根据model类型和data类型进行筛选。

在MultiModelLoader的buildLoadData方法中会依次调用包含的ModelLoader的buildLoadData方法:

@Override
public LoadData<Data> buildLoadData(@NonNull Model model, int width, int height,
    @NonNull Options options) {
  Key sourceKey = null;
  int size = modelLoaders.size();
  // 收集由ModelLoader构建的LoadData中的DataFetcher。
  List<DataFetcher<Data>> fetchers = new ArrayList<>(size);
  //noinspection ForLoopReplaceableByForEach to improve perf
  for (int i = 0; i < size; i++) {
    ModelLoader<Model, Data> modelLoader = modelLoaders.get(i);
    // 匹配支持model的ModelLoader。
    if (modelLoader.handles(model)) {
      LoadData<Data> loadData = modelLoader.buildLoadData(model, width, height, options);
      if (loadData != null) {
        sourceKey = loadData.sourceKey;
        // 添加DataFetcher。
        fetchers.add(loadData.fetcher);
      }
    }
  }
  // 重新new一个LoadData,保存收集的DataFetcher。
  return !fetchers.isEmpty() && sourceKey != null
      ? new LoadData<>(sourceKey, new MultiFetcher<>(fetchers, exceptionListPool)) : null;
}

该方法中,依次匹配model对应的ModelLoader,然后构建LoadData。但是并不直接使用构建的LoadData,仅取出其中的DataFetcher。最后利用MultiFetcher对象保存DataFetcher列表,新new一个LoadData返回。

当model为String类型时,经过层层筛选后,最终仅剩一个LoadData。LoadData中的fetcher成员为MultiFetcher实例,包含两个HttpUrlFetcher实例。

回到SourceGenerator的startNext方法的while循环体中:

public boolean startNext() {
  ···
  while (!started && hasNextModelLoader()) {
    loadData = helper.getLoadData().get(loadDataListIndex++);
    // DiskCacheStrategy.AUTOMATIC的isDataCacheable方法中判断dataSource是否为DataSource.REMOTE,
    // 这里getDataSource方法调用的是HttpUrlFetcher的getDataSource,返回一致,if条件判断通过。
    if (loadData != null
        && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
        || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
      started = true;
      loadData.fetcher.loadData(helper.getPriority(), this);
    }
  }
  ···
}

下面进入DataFetcher的loadData方法,开始从model拉取源数据。

DataFetcher加载数据

从上文得知此处的loadData.fetcher为MultiFetcher实例,查看它的loadData方法:

@Override
public void loadData(
    @NonNull Priority priority, @NonNull DataCallback<? super Data> callback) {
  this.priority = priority;
  this.callback = callback;
  exceptions = throwableListPool.acquire();
  // 根据当前索引获取DataFetcher,currentIndex初始为0。
  fetchers.get(currentIndex).loadData(priority, this);
}

从上文得知此时fetchers保存了两个HttpUrlFetcher实例,继续看HttpUrlFetcher的loadData方法:

@Override
public void loadData(@NonNull Priority priority,
    @NonNull DataCallback<? super InputStream> callback) {
  long startTime = LogTime.getLogTime();
  try {
    // 获取到源数据的InputStream。
    InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
    // 将InputStream回传给SourceGenerator处理。
    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));
    }
  }
}

接着看loadDataWithRedirects方法:

private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
      Map<String, String> headers) throws IOException {
  // 判断重定向次数是否达到了5次。 
  if (redirects >= MAXIMUM_REDIRECTS) {
    throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
  } 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 {
      // 产生重定向时,lastUrl会传入上一次的url,将前后url进行比较,如果是一样的,表示陷入了死循环中。
      if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
        throw new HttpException("In re-direct loop");

      }
    } catch (URISyntaxException e) {
      // Do nothing, this is best effort.
    }
  }

  // 调用url的openConnection方法,返回HttpURLConnection实例。
  urlConnection = connectionFactory.build(url);
  // 以下就是平常使用的网络操作的代码。
  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.
  // 禁用HttpURLConnection的自动重定向,自行处理重定向。
  urlConnection.setInstanceFollowRedirects(false);

  // 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();
  // 若view从detached或cancel加载,则返回null。外层会根据空值进行相应处理。
  if (isCancelled) {
    return null;
  }
  final int statusCode = urlConnection.getResponseCode();
  if (isHttpOk(statusCode)) {
    // 状态码为2xx表示成功,从urlConnection获取InputStream返回。
    return getStreamForSuccessfulRequest(urlConnection);
  } else if (isHttpRedirect(statusCode)) {
    // 状态码为3xx表示重定向,从表头获取"Location"字段值作为重定向地址。
    String redirectUrlString = urlConnection.getHeaderField("Location");
    if (TextUtils.isEmpty(redirectUrlString)) {
      throw new HttpException("Received empty or null redirect url");
    }
    URL redirectUrl = new URL(url, redirectUrlString);
    // 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 {
    throw new HttpException(urlConnection.getResponseMessage(), statusCode);
  }
}

HttpUrlFetcher中就是使用我们熟悉的HttpURLConnection网络操作代码,返回InputStream后,通过回调接口传给SourceGenerator处理,看它的onDataReady方法:

@Override
public void onDataReady(Object data) {
  // 根据磁盘缓存策略决定是先进行缓存还是直接回调出去。
  DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
  // diskCacheStrategy默认为DiskCacheStrategy.AUTOMATIC,判断dataSource是否为DataSource.REMOTE,这里满足条件。
  // 因此只要data不为空,就先进行缓存。
  if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
    // dataToCache此时赋值为InputStream。
    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.
    // 此处的cb即为SourceGenerator创建时传入的DecodeJob实例。
    cb.reschedule();
  } else {
    cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
        loadData.fetcher.getDataSource(), originalKey);
  }
}

又回到了DecodeJob的reschedule方法中,前面分析过,此方法最终又回DecodeJob的runGenerators的方法中,因为当前阶段仍为SOURCE未改变,所以又执行了SourceGenerator的startNext方法:

public boolean startNext() {
  // 经过上面的源数据获取,此时dataToCache为InputStream。
  if (dataToCache != null) {
    Object data = dataToCache;
    dataToCache = null;
    cacheData(data);
  }
  
  if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
    return true;
  }
  sourceCacheGenerator = null;
  ···
}

进入cacheData方法:

private void cacheData(Object dataToCache) {
  longstartTime = LogTime.getLogTime();
  try {
    // 从Registry中查找dataToCache的类型对应的Encoder(Encoder负责写入磁盘缓存),此处得到StreamEncoder实例。
    Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
    DataCacheWriter<Object> writer =
        new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
    // 构造缓存key。
    originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
    // 获取DiskCache,默认返回DiskLruCacheWrapper。在它的put方法中通过writer将数据写入File,然后记录操作日志到
    // journal文件中(常规的磁盘缓存操作)。而在writer中又是通过StreamEncoder从InputStream写入到File。
    helper.getDiskCache().put(originalKey, writer);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      Log.v(TAG, "Finished encoding source to cache"
          + ", key: " + originalKey
          + ", data: " + dataToCache
          + ", encoder: " + encoder
          + ", duration: " + LogTime.getElapsedMillis(startTime));
    }
  } finally {
    // 完成磁盘缓存后,关闭流和释放连接。
    loadData.fetcher.cleanup();
  }
  
  // 给sourceCacheGenerator成员赋值。
  sourceCacheGenerator =
      new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
}

执行完cacheData方法,返回startNext方法。往下执行,此时sourceCacheGenerator已赋值,执行它的startNext方法:

@Override
public boolean startNext() {
  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;
      // 获取到File类型对应的ModelLoader集合。
      modelLoaders = helper.getModelLoaders(cacheFile);
      modelLoaderIndex = 0;
    }
  }

  loadData = null;
  boolean started = false;
  while (!started && hasNextModelLoader()) {
    // 依次获取ModelLoader创建LoadData,尝试可用的LoadData。
    ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
    loadData =
        modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
            helper.getOptions());
    // 判断LoadData中的DataFetcher尝试获取的数据的类型是否存在对应的LoadPath。
    if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
      started = true;
      // 通过LoadData中的DataFetcher加载数据。
      loadData.fetcher.loadData(helper.getPriority(), this);
    }
  }
  return started;
}

该方法中获取的ModelLoader有ByteBufferFileLoader、FileLoader、FileLoader、UnitModelLoader,通过ByteBufferFileLoader创建的LoadData就匹配上了,由它创建的ByteBufferFetcher获取DataClass为ByteBuffer.class,进入hasLoadPath方法:

boolean hasLoadPath(Class<?> dataClass) {
  return getLoadPath(dataClass) != null;
}

<Data> LoadPath<Data, ?, Transcode> getLoadPath(Class<Data> dataClass) {
  // 从Registry中查找。
  return glideContext.getRegistry().getLoadPath(dataClass, resourceClass, transcodeClass);
}

看Registry的getLoadPath方法,在本例中,此处dataClass为ByteBuffer.class,resourceClass为Object.class,transcodeClass为Drawable.class

@Nullable
public <Data, TResource, Transcode> LoadPath<Data, TResource, Transcode> getLoadPath(
    @NonNull Class<Data> dataClass, @NonNull Class<TResource> resourceClass,
    @NonNull Class<Transcode> transcodeClass) {
  LoadPath<Data, TResource, Transcode> result =
      loadPathCache.get(dataClass, resourceClass, transcodeClass);
  if (loadPathCache.isEmptyLoadPath(result)) {
    return null;
  } else if (result == null) {
    // 收集DecodePath集合。
    List<DecodePath<Data, TResource, Transcode>> decodePaths =
        getDecodePaths(dataClass, resourceClass, transcodeClass);
    // It's possible there is no way to decode or transcode to the desired types from a given
    // data class.
    if (decodePaths.isEmpty()) {
      result = null;
    } else {
      // 创建LoadPath对象,将收集到的DecodePath集合包装进去。
      result =
          new LoadPath<>(
              dataClass, resourceClass, transcodeClass, decodePaths, throwableListPool);
    }
    // 将创建的LoadPath保存起来。
    loadPathCache.put(dataClass, resourceClass, transcodeClass, result);
  }
  return result;
}

接着看getDecodePaths方法:

@NonNull
private <Data, TResource, Transcode> List<DecodePath<Data, TResource, Transcode>> getDecodePaths(
    @NonNull Class<Data> dataClass, @NonNull Class<TResource> resourceClass,
    @NonNull Class<Transcode> transcodeClass) {
  List<DecodePath<Data, TResource, Transcode>> decodePaths = new ArrayList<>();
  // 利用dataClass和resourceClass检索出注册的解码资源类型。
  // 需要满足注册Data类型为dataClass的超类且resourceClass为注册Resource类型的超类。
  List<Class<TResource>> registeredResourceClasses =
      decoderRegistry.getResourceClasses(dataClass, resourceClass);

  // 遍历注册的解码资源类型。
  for (Class<TResource> registeredResourceClass : registeredResourceClasses) {
    // 利用registeredResourceClass和transcodeClass检索出注册的转码资源类型。
    // 需要满足注册Resource类型为registeredResourceClass的超类且transcodeClass为注册Transcode类型的超类,
    // 或者transcodeClass为registeredResourceClass的超类,那么直接返回transcodeClass。
    List<Class<Transcode>> registeredTranscodeClasses =
        transcoderRegistry.getTranscodeClasses(registeredResourceClass, transcodeClass);

    // 遍历注册的转码资源类型。
    for (Class<Transcode> registeredTranscodeClass : registeredTranscodeClasses) {

      // 利用dataClass和registeredResourceClass检索出注册的ResourceDecoder。
      // 匹配条件同检索出注册的解码资源类型一致。
      List<ResourceDecoder<Data, TResource>> decoders =
          decoderRegistry.getDecoders(dataClass, registeredResourceClass);
      // 利用registeredResourceClass和registeredTranscodeClass检索出注册的ResourceTranscoder。
      // 匹配条件同检索出注册的转码资源类型一致,若registeredTranscodeClass为registeredResourceClass超类,则返回UnitTranscoder对象。
      ResourceTranscoder<TResource, Transcode> transcoder =
          transcoderRegistry.get(registeredResourceClass, registeredTranscodeClass);
      @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
      // 创建DecodePath,将检索到的ResourceDecoder集合和ResourceTranscoder包装进去。
      DecodePath<Data, TResource, Transcode> path =
          new DecodePath<>(dataClass, registeredResourceClass, registeredTranscodeClass,
              decoders, transcoder, throwableListPool);
      // 将DecodePath添加集合保存。
      decodePaths.add(path);
    }
  }
  return decodePaths;
}

该方法中通过<Data, TResource, Transcode>类型从Registry中检索出匹配的ResourceDecoder和ResourceTranscoder,使之能够将数据从Data类型解码转换成Transcode类型,然后利用DecodePath将它们包装进去。

ps:Glide注册的ResourceDecoder、ResourceTranscoder和<Data, TResource, Transcode>的对应关系可以查看ResourceDecoder映射表、ResourceTranscoder映射表

结合本文章例子,这里检索它们的作用是通过ByteBufferFileLoader将资源从File读取到ByteBuffer,然后通过ByteBufferBitmapDecoder将资源从ByteBuffer解码成Bitmap,再通过BitmapDrawableTranscoder对Bitmap进行处理,最终转换成BitmapDrawable。

返回到DataCacheGenerator的startNext方法中,执行完hasLoadPath方法满足条件,接下来就是调用fetcher的loadData方法(通过上面的分析得知fetcher为ByteBufferFetcher实例):

@Override
public void loadData(@NonNull Priority priority,
    @NonNull DataCallback<? super ByteBuffer> callback) {
  ByteBuffer result;
  try {
    // File -> MappedByteBuffer
    result = ByteBufferUtil.fromFile(file);
  } catch (IOException e) {
    if (Log.isLoggable(TAG, Log.DEBUG)) {
      Log.d(TAG, "Failed to obtain ByteBuffer for file", e);
    }
    callback.onLoadFailed(e);
    return;
  }

  // 回调传出MappedByteBuffer。
  callback.onDataReady(result);
}
@Override
public void onDataReady(Object data) {
  // 此时的cb为SourceGenerator实例。
  cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
}

看SourceGenerator的onDataFetcherReady回调:

@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
    DataSource dataSource, Key attemptedKey) {
  // This data fetcher will be loading from a File and provide the wrong data source, so override
  // with the data source of the original fetcher
  // 此时的cb为DecodeJob实例。替换数据来源回REMOTE。
  cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
}

继续看DecodeJob的onDataFetcherReady回调:

@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
    DataSource dataSource, Key attemptedKey) {
  this.currentSourceKey = sourceKey;
  // 此时的data为MappedByteBuffer。
  this.currentData = data;
  // 此时的fetcher为ByteBufferFetcher。
  this.currentFetcher = fetcher;
  this.currentDataSource = dataSource;
  this.currentAttemptingKey = attemptedKey;
  if (Thread.currentThread() != currentThread) {
    // 若当前线程和之前runGenerators方法执行时的线程不一致,则切换runReason,
    // 通过线程池再启动,在run方法中会执行decodeFromRetrievedData方法。
    runReason = RunReason.DECODE_DATA;
    callback.reschedule(this);
  } else {
    GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
    try {
      // 解码数据。
      decodeFromRetrievedData();
    } finally {
      GlideTrace.endSection();
    }
  }
}

这里直接执行decodeFromRetrievedData方法:

private void decodeFromRetrievedData() {
  if(Log.isLoggable(TAG, Log.VERBOSE)) {
    logWithTimeAndKey("Retrieved data", startFetchTime,
        "data: " + currentData
            + ", cache key: " + currentSourceKey
            + ", fetcher: " + currentFetcher);
  }
  Resource<R> resource = null;
  try {
    // 进行解码,返回资源的包装类。
    resource = decodeFromData(currentFetcher, currentData, currentDataSource);
  } catch (GlideException e) {
    e.setLoggingDetails(currentAttemptingKey, currentDataSource);
    throwables.add(e);
  }
  if (resource != null) {
    // 通知资源处理成功。
    notifyEncodeAndRelease(resource, currentDataSource);
  } else {
    runGenerators();
  }
}

接下来对数据进行解码转换处理,见《Glide v4 源码浅析(4)-into(下)》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值