Android 架构之Glide源码解读(中)

小知识,大挑战!本文正在参与“  程序员必备小知识  ”创作活动

本文同时参与 「掘力星计划」  ,赢取创作大礼包,挑战创作激励金

前言

在上一篇中,主要讲解了Glide 基础知识点以及with、load、into这三部曲中的with,知道了在with中Glide主要帮我们做了生命周期相互绑定的相关工作。在这一篇中,将会对load、into进一步解读相应的源码。

本篇解读的源码版本:4.11.0,读者也可以根据本章步骤,在AS中一步一步解读源码。

1、load 方法

  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable String string) {
    return asDrawable().load(string);
  }
复制代码

源码解析

这里有两个方法 asDrawableload 现在分别进行源码解读。

1.1 asDrawable 方法

  @NonNull
  @CheckResult
  public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
  }
复制代码

源码解析

这里调用了as 方法,继续追进

  @NonNull
  @CheckResult
  public <ResourceType> RequestBuilder<ResourceType> as(
      @NonNull Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
  }
复制代码

源码解析

到这,我们应该知道 asDrawable 方法最终 返回的是 RequestBuilder 对象,然后调用 load 方法。接下来就该分析 load方法是怎样走的。

1.2 load 方法

  @NonNull
  @Override
  @CheckResult
  public RequestBuilder<TranscodeType> load(@Nullable String string) {
    return loadGeneric(string);
  }
复制代码

源码解析

这里调用了 loadGeneric 方法继续追进。

  @NonNull
  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }
复制代码

源码解析

从这可以看出,loadGeneric 将对应参数(图片地址) 赋值给当前类的全局变量,最后再将该类返回。

1.3 图解总结

这里虽然简单,但还是用一张图来总结一下,load的整个流程。

Glide_with_load.png

2、into 方法

温馨提示:这里过程有点长,因为几乎所有的Glide逻辑都在这个方法里面。建议收藏关注一波,确保在足够多的空闲时间时再来捋一遍。

 @NonNull
  public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    Util.assertMainThread();
	...略
    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions,
        Executors.mainThreadExecutor());
  }
复制代码

源码解析

这里首先进行了是否为主线程的处理,其次调用了 into 方法,进去看看。

  private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> options,
      Executor callbackExecutor) {

	//构建 Request  对象
    Request request = buildRequest(target, targetListener, options, callbackExecutor);

    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      //这里是 请求失败重试判断,看是否重试
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        previous.begin();
      }
      return target;
    }
	//这里是正常请求
    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);
    return target;
  }
复制代码

源码解析

这里 先是进行了 Request 对象的构建,其次进行了 当前 Request 是否是新请求以及是否要重试,最后通过 requestManager.track 进行网络请求。先来分析一下 Request 对象的构建,进入buildRequest 方法。

2.1 开启 buildRequest 支线

  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) {

	...略

    Request mainRequest =
        buildThumbnailRequestRecursive(
            requestLock,
            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(
            requestLock,
            target,
            targetListener,
            errorRequestCoordinator,
            errorBuilder.transitionOptions,
            errorBuilder.getPriority(),
            errorOverrideWidth,
            errorOverrideHeight,
            errorBuilder,
            callbackExecutor);
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }
复制代码

源码解析

从这里可以看出,先是通过 buildThumbnailRequestRecursive 方法构建了 mainRequest 变量 ,如果没有失败请求(重试),那就直接返回。下面的也是处理因为失败的重试请求,最终也是返回了 Request 类型的变量。我们就不看重试的,直接进入 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) {
 	  ...略
      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);
    }
  }

复制代码

源码解析

从这可以看出,这里最多会有俩个请求 一个 fullRequest 正常状态的请求 ,thumbRequest 图标缩略图的请求。而正常请求 fullRequest 又是通过 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);
  }
复制代码

源码解析

这里调用了 SingleRequest.obtain 方法,继续追进。

  public static <R> SingleRequest<R> obtain(
      Context context,
      GlideContext glideContext,
      Object requestLock,
      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) {
    return new SingleRequest<>(
        context,
        glideContext,
        requestLock,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        engine,
        animationFactory,
        callbackExecutor);
  }
复制代码

源码解析

这个方法返回了 SingleRequest 对象。到这,buildRequest 支线已经走完了。这里的 SingleRequest 对象,将会依次返回到主线,接下来回到主线看看。

2.2 结束 buildRequest 支线,回到主线。

避免来回翻,这里再贴主线代码。

  private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> options,
      Executor callbackExecutor) {

	//构建 Request  对象
    Request request = buildRequest(target, targetListener, options, callbackExecutor);

    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      //这里是 请求失败重试判断,看是否重试
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        previous.begin();
      }
      return target;
    }
	//这里是正常请求
    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);
    return target;
  }
复制代码

总结

到这,我们应该能明白 buildRequest 方法返回的 Request 对象,里面阔能会含有 缩略图 请求的封装。现在继续 看 requestManager.track 方法。

2.3 开启 requestManager.track 支线

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

源码解析

这里分别调用了 targetTracker.trackrequestTracker.runRequest 方法,依次进去看看。

  • targetTracker.track
  public void track(@NonNull Target<?> target) {
    targets.add(target);
  }
复制代码

源码解析

这里我们可以理解为 将这个任务添加至某个集合里面。

  • requestTracker.runRequest
  /** Starts tracking the given request. */
  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);
    }
  }
复制代码

源码解析

这里首先有两个集合,分别为:正在执行队列、暂停后等待执行队列。先是将该请求加入正在执行队列,然后判断当前Glide是否为暂停状态,如果否,则直接运行执行队列,如果是则清空正在执行队列,将当前请求加入等待执行队列。现在我们肯定是看执行的,于是进入begin方法看看。

1.png

如图所示

进入SingleRequest 里面的 begin 方法

  @Override
  public void begin() {
    synchronized (requestLock) {
      assertNotCallingCallbacks();
      stateVerifier.throwIfRecycled();
      startTime = LogTime.getLogTime();
      
	  ...略

	  //如果当前图片已经正在运行了,
      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;
      //进行宽高的判断,宽高是否大于0
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      	//满足进入该方法
        onSizeReady(overrideWidth, overrideHeight);
      } else {
        target.getSize(this);
      }

     ...略
    }
  }
复制代码

源码解析

从这可以看出,这里进行了一系列的逻辑判断,最终会进入 onSizeReady 方法。进入看看。

public final class SingleRequest<R> implements Request, SizeReadyCallback, ResourceCallback {

...略

 @Override
  public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    synchronized (requestLock) {
      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.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, // SingleRequest implements Request, SizeReadyCallback, ResourceCallback
              callbackExecutor);
      if (status != Status.RUNNING) {
        loadStatus = null;
      }
    }
  }

...略
}
复制代码

源码解析

从这可以看出,如果这里status 不等于上面设置的 等待状态,那么将直接终止。过后将对应的 status 设置为运行状态,随后根据比例进行了 宽高计算,最后调用了 engine.load 方法,并且传入了 当前对象 this ,而当前类实现了 Request, SizeReadyCallback, ResourceCallback 对应的接口,用来响应回调。我们进入engine.load 该方法看看。

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

    //如果成功从缓存里面拿到对应数据了,那么调用onResourceReady方法将缓存数据返回给上一层。
    cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
    return null;
  }
复制代码

源码解析

这里首先根据相应的请求生成了对应的缓存key ,然后调用 loadFromMemory 方法查询是否有对应缓存,如果有则通过 cb.onResourceReady 方法将对应缓存数据返回给上一层;如果没有则调用 waitForExistingOrStartNewJob 方法。

我们先进入 loadFromMemory 方法看看

  @Nullable
  private EngineResource<?> loadFromMemory(
      EngineKey key, boolean isMemoryCacheable, long startTime) {
    //判断是否开启缓存
    if (!isMemoryCacheable) {
      return null;
    }
	//读取活动缓存
    EngineResource<?> active = loadFromActiveResources(key);
    if (active != null) {
      return active;
    }
	//读取内存缓存
    EngineResource<?> cached = loadFromCache(key);
    if (cached != null) {
      return cached;
    }
    return null;
  }
复制代码

源码解析

从这段代码可以看出,如果没开启缓存,返回null,如果没有活动缓存则读取内存缓存,如果其中一个有缓存则返回对应缓存,如果两个都没有则返回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) {
	
	// 从工作队列中通过key 去寻找是否有 对应的 工作引擎
    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);
    }

   //如果没有则根据对应 key 创建对应的工作引擎
    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);

	//创建对应的解码器
    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);

	//将对应的工作引擎 添加至map中
    jobs.put(key, engineJob);

	//向对应的工作引擎添加可回调的功能
    engineJob.addCallback(cb, callbackExecutor);

	//开始工作,调用解码器
    engineJob.start(decodeJob);

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

源码解析

这里先是从对应的工作引擎Map查询是否存在已有引擎,如果没有则创建对应的工作引擎以及对应的解码器引擎,然后相互绑定对应的信息,最后调用engineJob.start方法开始工作。接下来进入该方法看看。

  public synchronized void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor =
        decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }
复制代码

源码解析

看到这样的代码 executor.execute 就能直接联想到 DecodeJob 这个类一定实现了 Runnable 接口以及核心逻辑也在对应的run方法里面,也是在这开启了线程(面试官最喜欢问的),接下来直接定位对应方法。

  @Override
  public void run() {
    GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
    DataFetcher<?> localFetcher = currentFetcher;
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      runWrapped();
    } catch (CallbackException e) {

      throw e;
    } catch (Throwable t) {
      if (stage != Stage.ENCODE) {
        throwables.add(t);
        notifyFailed();
      }
      if (!isCancelled) {
        throw t;
      }
      throw t;
    } finally {
      if (localFetcher != null) {
        localFetcher.cleanup();
      }
      GlideTrace.endSection();
    }
  }
复制代码

源码解析

这里调用了 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);
    }
  }
复制代码

源码解析

我们先进入 初始化里面,我们从上往下依次解读源码,先看看 getNextStage 方法,传入的是 INITIALIZE,那么

  private Stage getNextStage(Stage current) {
    switch (current) {
      case INITIALIZE:
      	//如果此请求应尝试解码缓存的资源数据,则返回 true。
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE
            : getNextStage(Stage.RESOURCE_CACHE);
       //如果此请求应尝试解码缓存的源数据,则返回 true。
      case RESOURCE_CACHE:
        return diskCacheStrategy.decodeCachedData()
            ? Stage.DATA_CACHE
            : getNextStage(Stage.DATA_CACHE);
      case DATA_CACHE:
		//如果用户选择仅从缓存中检索资源,则跳过从源加载。
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
  }
复制代码

源码解析

我们先假设不使用任何缓存,或者图片是第一次加载(缓存没数据),那么代码先进入 INITIALIZE,然后递归调用 参数为 Stage.RESOURCE_CACHE,最终会到 case DATA_CACHE ,接着进行 onlyRetrieveFromCache 判断,如果 这个为 true,该图片加载直接完成,否则就为 Stage.SOURCE

也就是说,如果,你的代码是这样写的。

final String url = "https://img1.baidu.com/it/u=4186787118,517350218&fm=26&fmt=auto&gp=0.jpg";
//除了生命周期,其他的功能都由into方法给干了
Glide.with(this).load(url)
        .onlyRetrieveFromCache(true)
        .into(iv_image1);
复制代码

那么你的图片,在没有本地缓存的情况下,永远加载不了图片!永远!Forever!

好了继续回到解读源码中

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

源码解析

刚刚我们解读了 方法 getNextStage 在正常情况下会返回 Stage.SOURCE ,那么进入 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);
    }
  }
复制代码

源码解析

这里的 stageSOURCE 也就是说, 返回的是:SourceGenerator。继续回到上一层,接着调用了 runGenerators 方法,进去看看。

  private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    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();
    }
  }
复制代码

源码解析

这里一看有个whlie循环,看最后一个条件判断,调用了currentGenerator.startNext(),进去看看。

2.png

如图所示

因为刚刚 得到的是 SourceGenerator,所以进入该类的这个方法。

  @Override
  public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }
	
	//判断资源加载器是否为空,以及判断资源加载器加载的数据是否成功
    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
      return true;
    }
    //如果前面没有成功获取数据,那么后面将会尝试从缓存里面拿取数据。
    sourceCacheGenerator = null;
    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
              || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        startNextLoad(loadData);
      }
    }
    return started;
  }
复制代码

源码解析

这里首先 调用了方法 cacheData 向 生成器 **sourceCacheGenerator ** 赋值,随后进行非空判断,最后 调用了方法 startNext,进去看看。

  @Override
  public boolean startNext() {
    while (modelLoaders == null || !hasNextModelLoader()) {
    
	...略
	
    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;
  }
复制代码

源码解析

这里我们可以看到 调用了 modelLoader.buildLoadData 方法返回的 loadData,所以继续进入该方法。

3.png

如图所示

进入该类,该方法。

  @Override
  public LoadData<InputStream> buildLoadData(
      @NonNull GlideUrl model, int width, int height, @NonNull Options options) {
    GlideUrl url = model;
    if (modelCache != null) {
      url = modelCache.get(model, 0, 0);
      if (url == null) {
        modelCache.put(model, 0, 0, model);
        url = model;
      }
    }
    int timeout = options.get(TIMEOUT);
    return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
  }
复制代码

源码解析

这里直接定位到最后一句,实例化了LoadData,里面构造参数又实例化了 HttpUrlFetcher 对象,直接定位到HttpUrlFetcher.loadData 方法。

  @Override
  public void loadData(
      @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    try {
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
      callback.onDataReady(result);
    } catch (IOException e) {
    } finally {
    }
  }
复制代码

源码解析

这里调用了 loadDataWithRedirects 方法拿到对应的流文件,进去看看这个方法怎么获取的。

  private InputStream loadDataWithRedirects(
      URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException {
      
    ...略
    
    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);
    urlConnection.setInstanceFollowRedirects(false);
    urlConnection.connect();
    stream = urlConnection.getInputStream();
    if (isCancelled) {
      return null;
    }
    final int statusCode = urlConnection.getResponseCode();
    if (isHttpOk(statusCode)) {
      //网络连接成功,并且code为正常的200
      return getStreamForSuccessfulRequest(urlConnection);
    } else if (isHttpRedirect(statusCode)) {
      //处理重定向问题
      String redirectUrlString = urlConnection.getHeaderField("Location");
      if (TextUtils.isEmpty(redirectUrlString)) {
        throw new HttpException("Received empty or null redirect url");
      }
      URL redirectUrl = new URL(url, redirectUrlString);
      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);
    }
  }
复制代码

源码解析

解析到这,终于到连接网络这了,这里先是用HttpURLConnection 连接网络,连接成功后如果code为200则直接通过方法getStreamForSuccessfulRequest返回对应流,如果为重定向的code,那么解析对应重定向的地址,再次递归调用该方法。现在回到上一步,看看这个方法返回的网络流是怎么处理的。

  @Override
  public void loadData(
      @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    try {
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
      callback.onDataReady(result);
    } catch (IOException e) {
    } finally {
    }
  }
复制代码

源码解析

从这可以看出,这里调用了 callback.onDataReady 将流,返回给了上一层,接下来该去寻找实现这个方法的接收方了。

4.png

如图所示

因为我们是从DataCacheGenerator 进入的网络请求,那么返回也会到DataCacheGenerator这里面。

  @Override
  public void onDataReady(Object data) {
    cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
  }
复制代码

源码解析

继续追进方法onDataFetcherReady,快完了。

5.png

如图所示

我们刚开始通过DecodeJob这个类一步一步进入的,那么返回也要是这个类。

  @Override
  public void onDataFetcherReady(
      Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;
    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();
      }
    }
  }
复制代码

源码解析

这里有一个是否主线程的判断,因为我们这个返回是从网络连接返回的,所以当前线程为子线程,就只能进else里面。在else里面调用了方法 decodeFromRetrievedData,进去看看。

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

源码解析

这里调用了 decodeFromData 方法,返回了 Resource 对象。因为等会要回到这里,处理下面的逻辑,所以再开一个支线。

2.3.1 开启 decodeFromData 支线

  private <Data> Resource<R> decodeFromData(
      DataFetcher<?> fetcher, Data data, DataSource dataSource) throws GlideException {
    try {
      if (data == null) {
        return null;
      }
      long startTime = LogTime.getLogTime();
      Resource<R> result = decodeFromFetcher(data, dataSource);
      return result;
    } finally {
      fetcher.cleanup();
    }
  }
复制代码

源码解析

不想多说了,直接进入 decodeFromFetcher 方法。

  private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
      throws GlideException {
    LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
    return runLoadPath(data, dataSource, path);
  }
复制代码

源码解析

高情商:这嵌套的真好;低情商:这尼玛还没完。

这里调用了 runLoadPath 方法,追进。

  private <Data, ResourceType> Resource<R> runLoadPath(
      Data data, DataSource dataSource, LoadPath<Data, ResourceType, R> path)
      throws GlideException {
    Options options = getOptionsWithHardwareConfig(dataSource);
    DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
    try {
      return path.load(
          rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
    } finally {
      rewinder.cleanup();
    }
  }

复制代码

源码解析

继续进入 path.load,不信了,还能一直下去。

  public Resource<Transcode> load(
      DataRewinder<Data> rewinder,
      @NonNull Options options,
      int width,
      int height,
      DecodePath.DecodeCallback<ResourceType> decodeCallback)
      throws GlideException {
    List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire());
    try {
      return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
    } finally {
      listPool.release(throwables);
    }
  }
复制代码

源码解析

继续追进 loadWithExceptionList 方法。

  private Resource<Transcode> loadWithExceptionList(
      DataRewinder<Data> rewinder,
      @NonNull Options options,
      int width,
      int height,
      DecodePath.DecodeCallback<ResourceType> decodeCallback,
      List<Throwable> exceptions)
      throws GlideException {
    Resource<Transcode> result = null;
    for (int i = 0, size = decodePaths.size(); i < size; i++) {
      DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i);
      try {
        result = path.decode(rewinder, width, height, options, decodeCallback);
      } catch (GlideException e) {
        exceptions.add(e);
      }
      if (result != null) {
        break;
      }
    }
    if (result == null) {
      throw new GlideException(failureMessage, new ArrayList<>(exceptions));
    }
    return result;
  }
复制代码

源码解析

哇,要蚌不住了,进入 path.decode 方法。

  public Resource<Transcode> decode(
      DataRewinder<DataType> rewinder,
      int width,
      int height,
      @NonNull Options options,
      DecodeCallback<ResourceType> callback)
      throws GlideException {
    Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
    Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
    return transcoder.transcode(transformed, options);
  }
复制代码

源码解析

蚌不住了,进入 transcoder.transcode 看看。

6.png

如图所示

看上面注释 感觉快完了,这里我们随便选一个进去看看。

public class BitmapBytesTranscoder implements ResourceTranscoder<Bitmap, byte[]> {

...略
  @Nullable
  @Override
  public Resource<byte[]> transcode(
      @NonNull Resource<Bitmap> toTranscode, @NonNull Options options) {
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    toTranscode.get().compress(compressFormat, quality, os);
    toTranscode.recycle();
    return new BytesResource(os.toByteArray());
  }
...略
}
复制代码

源码解析

哈哈哈哈,终于给我找到了,看到没,将流转化为 Bitmap,然后释放,最后将转换好的资源依次返回。

这条支线终于走完了,继续回到2.3

2.3.2 结束 decodeFromData 支线

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

源码解析

刚刚我们专门开启了一个支线分析了 decodeFromData 里面的逻辑,返回的resource是转化好了的图片资源 ,如果为空,则调用 刚刚我们分析过的方法 runGenerators ,如果不为空则调用 notifyEncodeAndRelease,进入该方法看看。

  private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
	...略

    notifyComplete(result, dataSource);

	...略
  }
复制代码

源码解析

进入该方法

  private void notifyComplete(Resource<R> resource, DataSource dataSource) {
    setNotifiedOrThrow();
    callback.onResourceReady(resource, dataSource);
  }
复制代码

源码解析

在这终于调用了 callback.onResourceReady 这个回调了,感觉快要结束了,但是在这又要开启一条支线了。

2.3.3 开启 callback.onResourceReady 支线

  @Override
  public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    synchronized (this) {
      this.resource = resource;
      this.dataSource = dataSource;
    }
    notifyCallbacksOfResult();
  }
复制代码

源码解析

继续追进 notifyCallbacksOfResult

  void notifyCallbacksOfResult() {
    ResourceCallbacksAndExecutors copy;
    Key localKey;
    EngineResource<?> localResource;
    synchronized (this) {
      stateVerifier.throwIfRecycled();
      if (isCancelled) {
        resource.recycle();
        release();
        return;
      } else if (cbs.isEmpty()) {
        throw new IllegalStateException("Received a resource without any callbacks to notify");
      } else if (hasResource) {
        throw new IllegalStateException("Already have resource");
      }
      engineResource = engineResourceFactory.build(resource, isCacheable, key, resourceListener);
      copy = cbs.copy();
      incrementPendingCallbacks(copy.size() + 1);
      localKey = key;
      localResource = engineResource;
    }
    engineJobListener.onEngineJobComplete(this, localKey, localResource);
    for (final ResourceCallbackAndExecutor entry : copy) {
      entry.executor.execute(new CallResourceReady(entry.cb));
    }
    decrementPendingCallbacks();
  }
复制代码

源码解析

这里对资源进行了一系列处理,最后调用了 engineJobListener.onEngineJobComplete 方法

@Override
  public synchronized void onEngineJobComplete(
      EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
    // A null resource indicates that the load failed, usually due to an exception.
    if (resource != null && resource.isMemoryCacheable()) {
      activeResources.activate(key, resource);
    }

    jobs.removeIfCurrent(key, engineJob);
  }
复制代码

源码解析

这里调用了 activeResources.activate 方法,继续追进

  synchronized void activate(Key key, EngineResource<?> resource) {
    ResourceWeakReference toPut =
        new ResourceWeakReference(
            key, resource, resourceReferenceQueue, isActiveResourceRetentionAllowed);

    ResourceWeakReference removed = activeEngineResources.put(key, toPut);
    if (removed != null) {
      removed.reset();
    }
  }

复制代码

源码解析

在这可以看出,这里向活动缓存队列里面添加了对应图片的缓存,到这条支线也走完了。

2.3.4 结束 callback.onResourceReady 支线

现在回到最外层的 SingleRequestonResourceReady

  @Override
  public void onResourceReady(Resource<?> resource, DataSource dataSource) {
    stateVerifier.throwIfRecycled();
    Resource<?> toRelease = null;
    try {
      synchronized (requestLock) {
		...略
        onResourceReady((Resource<R>) resource, (R) received, dataSource);
      }
    } finally {
      if (toRelease != null) {
        engine.release(toRelease);
      }
    }
  }
复制代码

源码解析

这里进行一系列的处理,最终会调用onResourceReady 方法。

 private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
    // We must call isFirstReadyResource before setting status.
    boolean isFirstResource = isFirstReadyResource();
    status = Status.COMPLETE;
    this.resource = resource;
    isCallingCallbacks = true;
    try {
      boolean anyListenerHandledUpdatingTarget = false;
     
	  ...略 
      if (!anyListenerHandledUpdatingTarget) {
        Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
        target.onResourceReady(result, animation);
      }
    } finally {
      isCallingCallbacks = false;
    }

    notifyLoadSuccess();
  }
复制代码

源码解析

这里会调用 target.onResourceReady 这个方法。继续追进。

7.png

如图所示

因为这里是要给图片展示数据,这里就选择 ImageView 相关的。

  @Override
  public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
  	//判断是否有动画
    if (transition == null || !transition.transition(resource, this)) {
      setResourceInternal(resource);
    } else {
     //展示动画
      maybeUpdateAnimatable(resource);
    }
  }
复制代码

源码解析

这里有个是否存在动画的判断,没有就直接展示图片,所以直接定位到 方法 setResourceInternal

  private void setResourceInternal(@Nullable Z resource) {
    // Order matters here. Set the resource first to make sure that the Drawable has a valid and
    // non-null Callback before starting it.
    setResource(resource);
    maybeUpdateAnimatable(resource);
  }
复制代码

源码解析

这里依然进入setResource

8.png

如图所示

任选其一,随便进一个。

public class BitmapImageViewTarget extends ImageViewTarget<Bitmap> {

...略

  @Override
  protected void setResource(Bitmap resource) {
    view.setImageBitmap(resource);
  }
  
...略
}
复制代码

源码解析

哈哈哈哈哈哈哈哈哈,终于到达终点了!只想说!还有谁?一步一步分析进入,再一步一步回调出来。过程之艰辛。反正我坚持过来了,不知道读者有没有看到这里来。

2.4 图解总结

Glide_into.png

3、总结

到这里,还是总结一下,Glide的三部曲:with、load、into 。

  • with 具有生命周期相互绑定的功能
  • load 具有待加载的图片资源赋值(比如网络图片Url,本地文件File等)
  • into 具有图片处理的核心功能(图片加载、图片缓存等)

好了,相信看到这里,你应该对Glide源码有所了解了。在下一篇文章中,将会详细讲解Glide的缓存逻辑。

猜你喜欢

转载自juejin.im/post/7017397718679207949

相关文章