栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

前言

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

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

1、load 方法
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder load(@Nullable String string) {
    return asDrawable().load(string);
  }

源码解析

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

1.1 asDrawable 方法
  @NonNull
  @CheckResult
  public RequestBuilder asDrawable() {
    return as(Drawable.class);
  }

源码解析

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

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

源码解析

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

1.2 load 方法
  @NonNull
  @Override
  @CheckResult
  public RequestBuilder load(@Nullable String string) {
    return loadGeneric(string);
  }

源码解析

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

  @NonNull
  private RequestBuilder loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }

源码解析

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

1.3 图解总结

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

2、into 方法

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

 @NonNull
  public ViewTarget into(@NonNull ImageView view) {
    Util.assertMainThread();
	...略
    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
         null,
        requestOptions,
        Executors.mainThreadExecutor());
  }

源码解析

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

  private > Y into(
      @NonNull Y target,
      @Nullable RequestListener 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 target,
      @Nullable RequestListener targetListener,
      baseRequestOptions requestOptions,
      Executor callbackExecutor) {
    return buildRequestRecursive(
         new Object(),
        target,
        targetListener,
         null,
        transitionOptions,
        requestOptions.getPriority(),
        requestOptions.getOverrideWidth(),
        requestOptions.getOverrideHeight(),
        requestOptions,
        callbackExecutor);
  }

源码解析

这里直接调用了 buildRequestRecursive 方法,进去看看。

  private Request buildRequestRecursive(
      Object requestLock,
      Target target,
      @Nullable RequestListener targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions 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 target,
      RequestListener targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions 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 target,
      RequestListener targetListener,
      baseRequestOptions requestOptions,
      RequestCoordinator requestCoordinator,
      TransitionOptions 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  SingleRequest obtain(
      Context context,
      GlideContext glideContext,
      Object requestLock,
      Object model,
      Class transcodeClass,
      baseRequestOptions requestOptions,
      int overrideWidth,
      int overrideHeight,
      Priority priority,
      Target target,
      RequestListener targetListener,
      @Nullable List> requestListeners,
      RequestCoordinator requestCoordinator,
      Engine engine,
      TransitionFactory 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 into(
      @NonNull Y target,
      @Nullable RequestListener 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.track 和 requestTracker.runRequest 方法,依次进去看看。

  • targetTracker.track
  public void track(@NonNull Target target) {
    targets.add(target);
  }

源码解析

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

  • requestTracker.runRequest
  
  public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }

源码解析

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

如图所示

进入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 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  LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class resourceClass,
      Class transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map, 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  LoadStatus waitForExistingOrStartNewJob(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class resourceClass,
      Class transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map, 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 engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);

	//创建对应的解码器
    DecodeJob 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 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)
    .apply(RequestOptions.priorityOf(Priority.HIGH).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);
    }
  }

源码解析

这里的 stage 为 SOURCE 也就是说, 返回的是: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(),进去看看。

如图所示

因为刚刚 得到的是 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 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,所以继续进入该方法。

如图所示

进入该类,该方法。

  @Override
  public LoadData 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 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 headers) throws IOException {
      
    ...略
    
    urlConnection = connectionFactory.build(url);
    for (Map.Entry 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 callback) {
    long startTime = LogTime.getLogTime();
    try {
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
      callback.onDataReady(result);
    } catch (IOException e) {
    } finally {
    }
  }

源码解析

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

如图所示

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

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

源码解析

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

如图所示

我们刚开始通过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 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  Resource decodeFromData(
      DataFetcher fetcher, Data data, DataSource dataSource) throws GlideException {
    try {
      if (data == null) {
        return null;
      }
      long startTime = LogTime.getLogTime();
      Resource result = decodeFromFetcher(data, dataSource);
      return result;
    } finally {
      fetcher.cleanup();
    }
  }

源码解析

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

  private  Resource decodeFromFetcher(Data data, DataSource dataSource)
      throws GlideException {
    LoadPath path = decodeHelper.getLoadPath((Class) data.getClass());
    return runLoadPath(data, dataSource, path);
  }

源码解析

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

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

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

源码解析

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

  public Resource load(
      DataRewinder rewinder,
      @NonNull Options options,
      int width,
      int height,
      DecodePath.DecodeCallback decodeCallback)
      throws GlideException {
    List throwables = Preconditions.checkNotNull(listPool.acquire());
    try {
      return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
    } finally {
      listPool.release(throwables);
    }
  }

源码解析

继续追进 loadWithExceptionList 方法。

  private Resource loadWithExceptionList(
      DataRewinder rewinder,
      @NonNull Options options,
      int width,
      int height,
      DecodePath.DecodeCallback decodeCallback,
      List exceptions)
      throws GlideException {
    Resource result = null;
    for (int i = 0, size = decodePaths.size(); i < size; i++) {
      DecodePath 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 decode(
      DataRewinder rewinder,
      int width,
      int height,
      @NonNull Options options,
      DecodeCallback callback)
      throws GlideException {
    Resource decoded = decodeResource(rewinder, width, height, options);
    Resource transformed = callback.onResourceDecoded(decoded);
    return transcoder.transcode(transformed, options);
  }

源码解析

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

如图所示

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

public class BitmapBytesTranscoder implements ResourceTranscoder {

...略
  @Nullable
  @Override
  public Resource transcode(
      @NonNull Resource 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 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 resource, DataSource dataSource) {
	...略

    notifyComplete(result, dataSource);

	...略
  }

源码解析

进入该方法

  private void notifyComplete(Resource resource, DataSource dataSource) {
    setNotifiedOrThrow();
    callback.onResourceReady(resource, dataSource);
  }

源码解析

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

2.3.3 开启 callback.onResourceReady 支线
  @Override
  public void onResourceReady(Resource 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 支线

现在回到最外层的 SingleRequest的onResourceReady

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

源码解析

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

 private void onResourceReady(Resource 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 animation = animationFactory.build(dataSource, isFirstResource);
        target.onResourceReady(result, animation);
      }
    } finally {
      isCallingCallbacks = false;
    }

    notifyLoadSuccess();
  }

源码解析

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

如图所示

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

  @Override
  public void onResourceReady(@NonNull Z resource, @Nullable Transition 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


如图所示

任选其一,随便进一个。

public class BitmapImageViewTarget extends ImageViewTarget {

...略

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

源码解析

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

2.4 图解总结

3、总结

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

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

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/309716.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号