从源码分析Glide

从源码分析Glide,第1张

Glide中有很多方面都是我们需要关注,比如生命周期的管理,缓存机制,设计模式等。其中生命周期的管理应该是最简单的,我今天就不进行介绍了,今天主要从数据加载流程中分析缓存机制和相关的设计模式

Glide可以加载的数据源非常多,比如File,网络,Drawable等,今天主要以网络图片为例进行介绍,其他的类型加载流程是一样的,如下:

Glide.with(this)
    .load("https://img2.baidu.com/it/u=894463840,2154289921&fm=253&fmt=auto&app=138&f=JPEG?w=346&h=500")
    .into(findViewById(R.id.meizi_iv))

目录

一、确定Glide从哪级缓存中获取图片资源

1.load方法

2.into方法

二、从原始地址获取图片资源

三、将获取的数据进行缓存

四、将数据加入到内存缓存,并且展示到ImageView中

五、总结


一、确定Glide从哪级缓存中获取图片资源 1.load方法

with方法我们就跳过了,这里主要做的就是生命周期管理的 *** 作。我们直接进入load方法中查看:

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

这里有两个方法,我们先进入asDrawable中

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

进入as方法

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

as方法中创建了RequestBuilder对象,查看RequestBuilder的构造方法

  protected RequestBuilder(
      @NonNull Glide glide,
      RequestManager requestManager,
      Class transcodeClass,
      Context context) {
    this.glide = glide;
    this.requestManager = requestManager;
    this.transcodeClass = transcodeClass;
    this.context = context;
    this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
    this.glideContext = glide.getGlideContext();

    initRequestListeners(requestManager.getDefaultRequestListeners());
    apply(requestManager.getDefaultRequestOptions());
  }

这里我们要特别关注的是第三个参数transcodeClass,这个参数是我们刚刚穿进去的Drawable.class。

我们返回load方法中,asDrawable返回的是RequestBuilder对象,所以.load方法时RequestBuilder类调用的,我们查看load方法

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

查看loadGeneric方法

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

这里我们记住的是RequestBuilder中的model参数,这个参数就是数据源参数,也就是String类型的。load方法到这里就结束了,刚刚提到的两个点:trancodeClass是Drawable.class,model为String类型的数据源

2.into方法

从上面我们直到了,这个into方法是在RequestBuilder中的,查看into方法源码

public ViewTarget into(@NonNull ImageView view) {
    ....
    BaseRequestOptions requestOptions = this;
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions = requestOptions.clone().optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions = requestOptions.clone().optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.
      }
    }

    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions,
        Executors.mainThreadExecutor());
  }

 switch方法体中判断了图片的scaletype,并且设置到了RequestOptions中,这个RequestOptions是RequestBuilder本身(这里也要关注一下,之后某些属性要在RequestOptions中查找)

调用了into的重载方法,其中第一个参数调用了glideContext的buildImageView方法,进入查看:

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

查看buildTarget方法,要注意第二个参数是我们上面提到的transcodeClass,也就是Drawable.class

  public  ViewTarget buildTarget(
      @NonNull ImageView view, @NonNull Class clazz) {
    if (Bitmap.class.equals(clazz)) {
      return (ViewTarget) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
      return (ViewTarget) new DrawableImageViewTarget(view);
    } else {
      throw new IllegalArgumentException(
          "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
  }

根据条件判断,得出上面into方法中第一个参数类型就是DrawableImageViewTarget,我们继续查看上面调用的into重载方法

  private > Y into(
      @NonNull Y target,
      @Nullable RequestListener targetListener,
      BaseRequestOptions options,
      Executor callbackExecutor) {
    Preconditions.checkNotNull(target);
    ....

    Request request = buildRequest(target, targetListener, options, callbackExecutor);

    .....

    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
  }

篇幅有限,我留下了关键部分。第一个关键点是Request对象,第二个关键点是requestManager.track方法的调用。我们先看buildRequest方法

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

查看buildReuqestRecursive方法

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

    ...
    return errorRequestCoordinator;
  }

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) {
    if (thumbnailBuilder != null) {
      ...
      return coordinator;
    } else if (thumbSizeMultiplier != null) {
      ...
      return coordinator;
    } else {
      // Base case: no thumbnail.
      return obtainRequest(
          requestLock,
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight,
          callbackExecutor);
    }
  }

有两个判空:thumbnailBuilder和thumbSizeMultiplier,这个两个对象在没有调用设置的情况下为空,所以执行else条件,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);
  }

从这里可以看出来,上面所说的Request对象就是SingleRequest。

我们回到into方法,查看第二个点requestManager.track

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

targetTracker主要就是生命周期变化时调用的,重点是requestTracker的runRequest方法

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

调用request的begin方法,request我们刚刚说到了,是SingleRequest,查看SingleRequest中的begin方法

@Override
  public void begin() {
    synchronized (requestLock) {
      ....

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

      if (status == Status.COMPLETE) {
        onResourceReady(resource, DataSource.MEMORY_CACHE);
        return;
      }

      status = Status.WAITING_FOR_SIZE;
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        onSizeReady(overrideWidth, overrideHeight);
      } else {
        target.getSize(this);
      }

      if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
          && canNotifyStatusChanged()) {
        target.onLoadStarted(getPlaceholderDrawable());
      }
    }
  }

status初始化状态为PENDING,所以直接到第16行的if-else中的方法体。这里主要就是判断调用者是否有重写图片的宽高,没有的话会调用else中的方法,这里我们就不去追踪的,因为最后还会调到onSizeReady方法中。我们查看这个方法:

public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    synchronized (requestLock) {
      ....
      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,
              callbackExecutor);

      ...
    }
  }

engine类为Engine,调用了Engine的load方法(参数中requestOptions.getDiskCacheStrategy方法要注意,这个值递进查找可以知道是DiskCacheStrategy.AUTOMATIC),查看

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;

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

    // Avoid calling back while holding the engine lock, doing so makes it easier for callers to
    // deadlock.
    cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
    return null;
  }

有几个点我们关注一下:

(1)EngineKey:用此值在缓存中进行图片资源的查找

(2)loadFromMemory:从内存缓存中查找,我们暂时先不进去查看,因为是第一次加载,所以缓存中肯定是没有的。

所以会执行waitForExistingOrStartNewJob方法(参数中有个cb对象,这里我们要注意一下,从上面代码可知,cb对象为SingleRequest),进入查看:

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

    ....

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

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

创建EngineJob和DecodeJob对象,decodeJob传入到了EngineJob的start方法中,查看start方法:

  public synchronized void start(DecodeJob decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor =
        decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }

其实就是线程池执行一个任务,具体的执行方法还是在decodeJob的run方法中,所以我们直接查看DecodeJob的run方法:

@Override
  public void run() {
    ....
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      runWrapped();
    } 
    ....
  }

篇幅很多,但是关键的只有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);
    }
  }

runReason的初始值为INITIALIZE,所以先执行getNextStage方法,这个方法的作用就是将stage变化为下一个状态,查看getNextStage方法

  private Stage getNextStage(Stage current) {
    switch (current) {
      case INITIALIZE:
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE
            : getNextStage(Stage.RESOURCE_CACHE);
      case RESOURCE_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.
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
  }

刚刚我们说了,参数值是INITIALIZE,在判断条件中,调用了diskCacheStrategy.decodeCachedResource方法。上面我们已经知道了,diskCacheStrategy是DiskCacheStrategy.AUTOMATIC,所以我们查看它的decodeCachedResource方法,返回值固定为true。所以这里return的值为Stage.RESOURCE_CACHE

回到runWrapped方法中,继续执行getNextGenerator方法,这个方法的作用就是根据stage,来获取相应的Generator的对象

  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值为RESOURCE_CACHE,所以返回的类为ResourceCacheGenerator

返回到runWrapped方法中,所以currentGenerator为ResourceCacheGenerator(这个类我们要注意一下,它的作用是在内存缓存中查找图片资源),向下执行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;
      }
    }
    // We've run out of stages and generators, give up.
    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
      notifyFailed();
    }
  }

while方法体重前两个判断都没有问题,第三个条件是调用currentGenerator的startNext,currentGenerator是ResourceCacheGenerator,所以我们进入它的startNext方法中

  public boolean startNext() {
    List sourceIds = helper.getCacheKeys();
    if (sourceIds.isEmpty()) {
      return false;
    }
    ....
  }

其实startNext的关键代码很多,那为什么我只贴了上面的代码呢?刚刚我说到了,ResourceCacheGenerator是在内存缓存中查找,这时候我们是第一次从网络上获取,所以缓存中肯定没有,sourceIds是空的,返回false,所以又回到了runGenerator方法的while中,此时三个条件成立,进入方法体中,继续执行getNextStage和getNextGenerator。代码就不贴了,上面已经有了。

第一步:stage值此时是RESOURCE_CACHE,并且diskCacheStrategy.decodeCacheData返回值固定为true,所以stage变为DATA_CACHE。

第二步:而在getNextGenerator方法中,根据stage,返回的值为DataCacheGenerator,之后在runGenerators的while方法体中,将currentGenerator赋值为DataCacheGenerator,这个值的作用就是在磁盘缓存中查找图片资源。

第三步:执行while中的第三个条件,也就是DataCacheGenerator中的startNext方法

@Override
  public boolean startNext() {
    while (modelLoaders == null || !hasNextModelLoader()) {
      sourceIdIndex++;
      if (sourceIdIndex >= cacheKeys.size()) {
        return false;
      }
      .....
  }

和ResourceCacheGenerator一样,第一次加载图片。但是此时cacheKeys中其实有了一条数据,不过循环之后,还是会return false跳出。再次回到DecodeJob的runGenerators方法体中,继续执行getNextStage和getNextGenerator方法。

(1)getNextStage中,当stage为DATA_CACHE时,会根据onlyRetrieveFromCache来判断,这个值是什么意思呢?翻译字面意思就是:只在缓存中进行查找,所以这个值肯定是false,stage变为SOURCE

(2)currentGenerator变为SourceGenerator,这个类的作用就是从原始地址获取图片资源

在while方法体中,当stage为SOURCE时,执行了DecodeJob中的reschedule方法,然后return了,所以while方法就结束了。我们进入reschedule中

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

首先,runReason变为SWITCH_TO_SOURCE_SERVICE;其次调用了callback.reschedule方法。这个callback是哪个类呢?其实就是EngineJob,我们在上面的Engine的方法waitForExistingOrStartNewJob中可以找到根据:decodeJob是由decodeJobFactory的build方法中创建的,最后一个参数就是callback,也就是EngineJob类,所以我们查看EngineJob的reschedule方法

  @Override
  public void reschedule(DecodeJob job) {
    getActiveSourceExecutor().execute(job);
  }

其实还是线程池执行任务,也就是说,最后还是到了DecodeJob的run方法中,然后到了runWrapped方法中,上面已经说了这个流程了,在看一眼wrunWrapped方法

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

刚刚说了,runReason变为了SWITCH_TO_SOURCE_SERVICE,所以继续执行runGenerators方法,方法就不再贴了,上面有。

此时的currentGenerator为SourceGenerator,所以执行它的startNext方法,至此就已经确定了,缓存中没有想要的图片资源,要在原始地址中获取。

二、从原始地址获取图片资源

上面说到了执行SourceGenerator的startNext方法,我们看一下

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

(1)dataToCache表示要存储的缓存数据,此时原始数据还没有下载下来呢,更不用说缓存数据了,所以等于空

(2)sourceCacheGenerator就是上面说的DataCacheGenerator。作用先不说,这个对象暂时为空

(3)这里有一个loadData对象,类为LoadData,我们可以将这个LoadData理解为加载数据的包装类就可以了。

重点是在while方法,条件中,调用了hasNextModelLoader方法,进入查看(我们要在里面绕一大圈,所以要记住这里):

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

调用了helper的getLoadData方法,不用管helper是谁,点击去查看就行了

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

这里有两个点要注意:(1)isLoadDataSet初始值为false(2)loadData是一个集合。

第5行,model这个对象我们在最上面提到过,是我们的图片网络地址,是String类型。glideContext.getRegistry对象为ModlLoaderRegistry,我们查看它的getModelLoaders方法

  @NonNull
  public  List> getModelLoaders(@NonNull Model model) {
    return modelLoaderRegistry.getModelLoaders(model);
  }

查看getModelLoaders方法

  public  List getModelLoaders(@NonNull A model) {
    List modelLoaders = getModelLoadersForClass(getClass(model));
    if (modelLoaders.isEmpty()) {
      throw new NoModelLoaderAvailableException(model);
    }
    int size = modelLoaders.size();
    boolean isEmpty = true;
    List filteredLoaders = Collections.emptyList();
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0; i < size; i++) {
      ModelLoader loader = modelLoaders.get(i);
      if (loader.handles(model)) {
        if (isEmpty) {
          filteredLoaders = new ArrayList<>(size - i);
          isEmpty = false;
        }
        filteredLoaders.add(loader);
      }
    }
    if (filteredLoaders.isEmpty()) {
      throw new NoModelLoaderAvailableException(model, modelLoaders);
    }
    return filteredLoaders;
  }

先进入第2行的getModelLoadersForClass方法

  @NonNull
  private synchronized  List getModelLoadersForClass(
      @NonNull Class modelClass) {
    List loaders = cache.get(modelClass);
    if (loaders == null) {
      loaders = Collections.unmodifiableList(multiModelLoaderFactory.build(modelClass));
      cache.put(modelClass, loaders);
    }
    return loaders;
  }

cache是做ModelLoader缓存的,不用理会。我们看multiModelLoaderFactory的build方法

  @NonNull
  synchronized  List> build(@NonNull Class modelClass) {
    try {
      List> loaders = new ArrayList<>();
      for (Entry entry : entries) {
        if (alreadyUsedEntries.contains(entry)) {
          continue;
        }
        if (entry.handles(modelClass)) {
          alreadyUsedEntries.add(entry);
          loaders.add(this.build(entry));
          alreadyUsedEntries.remove(entry);
        }
      }
      return loaders;
    } catch (Throwable t) {
      alreadyUsedEntries.clear();
      throw t;
    }
  }

这里有一个entries对象,是Entry的List。Entry这个类是什么呢?我们先看一下这个类:

  private static class Entry {
    private final Class modelClass;
    @Synthetic final Class dataClass;
    @Synthetic final ModelLoaderFactory factory;

    public Entry(
        @NonNull Class modelClass,
        @NonNull Class dataClass,
        @NonNull ModelLoaderFactory factory) {
      this.modelClass = modelClass;
      this.dataClass = dataClass;
      this.factory = factory;
    }

    public boolean handles(@NonNull Class modelClass, @NonNull Class dataClass) {
      return handles(modelClass) && this.dataClass.isAssignableFrom(dataClass);
    }

    public boolean handles(@NonNull Class modelClass) {
      return this.modelClass.isAssignableFrom(modelClass);
    }
  }

modelClass:就是我们数据源的类型,这里是String类型

dataClass:是要转换的类型,比如想将输入的网络地址(字符串类型),转换InputStream。

factory:创建ModelLoader的工厂类

这些数据是谁提供呢?我们要看Glide这个类的构造方法,我这里截个图,感兴趣的可以自己去找找看,Glide所支持的类型转另一种类型非常多

 我们继续回到multiModelLoaderFactory的build方法中

(1)这个build方法作用到底是什么?其实就是想从系统提供的这些类型转换里找到可以对String类型进行转换的ModelLoader(我们暂时先不用管要转换成什么)。所以遍历了entries,然后调用了handles方法,参数为modelClass,目的就是刚刚说的,找到可以处理数据源为String类型的ModelLoader。

(2)找到对应的entry之后,又调用了MultiModelLoaderFactory的build方法,我们看一下这个方法

  private  ModelLoader build(@NonNull Entry entry) {
    return (ModelLoader) Preconditions.checkNotNull(entry.factory.build(this));
  }

工厂类去构建对应的ModelLoader

到这里呢,我们就拿到了相应的ModelLoader,当然不是最终的,后续还需要进行筛选,选出来的数据如下(还有几个我没写,一眼就能看出不符合,这两个是我一开始分不清的情况)

modelClassdataClassModelLoaderFactory
String.classInputStream.classDataUrlLoaderDataUrlLoader.StreamFactory
String.classInputStream.classStringLoaderStringLoader.StreamFactory

拿到ModelLoader集合,我们回到ModelLoaderRegistry的getModelLoaders方法中,我再次提出来

  public  List getModelLoaders(@NonNull A model) {
    List modelLoaders = getModelLoadersForClass(getClass(model));
    if (modelLoaders.isEmpty()) {
      throw new NoModelLoaderAvailableException(model);
    }
    int size = modelLoaders.size();
    boolean isEmpty = true;
    List filteredLoaders = Collections.emptyList();
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0; i < size; i++) {
      ModelLoader loader = modelLoaders.get(i);
      if (loader.handles(model)) {
        if (isEmpty) {
          filteredLoaders = new ArrayList<>(size - i);
          isEmpty = false;
        }
        filteredLoaders.add(loader);
      }
    }
    if (filteredLoaders.isEmpty()) {
      throw new NoModelLoaderAvailableException(model, modelLoaders);
    }
    return filteredLoaders;
  }

这里的modelLoaders就是刚刚获取的ModelLoader的集合,我们可以看到,对这个集合进行了遍历,其中调用了loader.handles方法。第一个Loader是DataUrlLoader,所以我们先查看DataUrlLoader的handles方法,如下:

  private static final String DATA_SCHEME_IMAGE = "data:image";

  @Override
  public boolean handles(@NonNull Model model) {
    return model.toString().startsWith(DATA_SCHEME_IMAGE);
  }

model是我们的网络图片地址,肯定不是以上面的字符串开头的,所以返回空。

第二个是StringLoader,我们查看它的handles方法,

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

固定返回true。

所以经过筛选后,只剩下一个符合的ModelLoader,那就是StringModel。

我们再次回到DecodeHelper的getLoadData方法,我在贴出来

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

对这个ModelLoader集合进行遍历,然后调用ModelLoader的buildLoadData方法,集合中只有一个值,那就是StringLoader,查看StringLoader的buildLoadData

  private final ModelLoader uriLoader;

  // Public API.
  @SuppressWarnings("WeakerAccess")
  public StringLoader(ModelLoader uriLoader) {
    this.uriLoader = uriLoader;
  }

  @Override
  public LoadData buildLoadData(
      @NonNull String model, int width, int height, @NonNull Options options) {
    Uri uri = parseUri(model);
    if (uri == null || !uriLoader.handles(uri)) {
      return null;
    }
    return uriLoader.buildLoadData(uri, width, height, options);
  }

我们发现,这类是ModelLoader,里面有一个参数uriLoader也是ModelLoader,并且StringLoader的buildLoadData的返回值,其实就是uriLoader的buildLoadData的返回值。我们仔细观察一下上面的buildLoadData方法,发现model(我们的数据源,也就是网络地址)转换为了Uri。也就是说数据源变成了Uri,所以处理数据源的类也就是变成了上面的uriLoader,uriLoader是从StringLoader的构造器中传进来的,我们看一下这个构造方法在哪里调用的,如图:

 三个地方调用,但是很明显,肯定是一个调用的地方,第二个和第三个是和File有关的。我们点进去递进查找,发现找到了MultiModelLoaderFactory的build方法,但是这个build不是上面说的build方法,这里的build参数多了一个输出类型的判断,并且返回值为ModelLoader,而不是ModelLoader的集合。在entries中查找输入类型为Uri.class,输入类型为InputStream.class的ModelLoader。找到的结果只有一个,如下

modelClassdataClassModelLoaderFactory
Uri.classInputStream.classHttpUriLoaderHttpUriLoader.Factory

所以从StringLoader的buildLoadData方法中,再跳到HttpUriLoader的buildLoadData方法中

  private final ModelLoader urlLoader;

  // Public API.
  @SuppressWarnings("WeakerAccess")
  public HttpUriLoader(ModelLoader urlLoader) {
    this.urlLoader = urlLoader;
  }

  @Override
  public LoadData buildLoadData(
      @NonNull Uri model, int width, int height, @NonNull Options options) {
    return urlLoader.buildLoadData(new GlideUrl(model.toString()), width, height, options);
  }

和StringLoader很像,所以我们需要知道urlLoader是谁,同样的,我们查看在哪里调用了HttpUriLoader的构造方法,只有一个地方,就是在HttpUriLoader.Factory的build中,

    public ModelLoader build(MultiModelLoaderFactory multiFactory) {
      return new HttpUriLoader(multiFactory.build(GlideUrl.class, InputStream.class));
    }

这里千万别糊涂,这里的build在获取ModelLoader的时候调用过了,对不对。

很不幸,这里的ModelLoader并没有明确表达,依然在multiModelLoaderFactory的build方法中去查找,输入类型为GlideUrl,输出类型为InputStream,结果只有一个,如下

modelClassdataClassModelLoaderFactory
GlideUrl.classInputStream.classHttpGlideUrlLoaderHttpGlideUrlLoader.Factory

所以呢,HttpUriLoader中的urlLoader是HttpGlideUrlLoader。我们再次从HttpUriLoader的buildLoadData跳转到HttpGlideUrlLoader的buildLoadData方法中,如下:

  @Override
  public LoadData buildLoadData(
      @NonNull GlideUrl model, int width, int height, @NonNull Options options) {
    // GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time
    // spent parsing urls.
    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,带有Fetcher的类都是实际进行数据获取的类,这里HttpUrlFetcher就是下载图片的核心类。

找到之后,我们就向上进行返回,回到了DecodeHelper的getLoadData方法,我再贴一下代码:

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

从上面的流程,我们直到,loadData中有两个数据。到这里,大家千万别忘了,getLoadData方法的调用是在SourceGenerator的hasNextModelLoader方法,而hasNextModelLoader方法的调用是在startNext方法中,我再贴一下startNext方法,帮大家回忆一下

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

OKOK,第二个十八弯也出来了。hasNextModelLoader返回值为true,这个我们刚刚的结论,对吧。

(1)第17行,从我们刚刚获取的LoadData集合中获取第一个loadData

(2)started变为true,然后执行startNextLoad方法

  private void startNextLoad(final LoadData toStart) {
    loadData.fetcher.loadData(
        helper.getPriority(),
        new DataCallback() {
          @Override
          public void onDataReady(@Nullable Object data) {
            if (isCurrentRequest(toStart)) {
              onDataReadyInternal(toStart, data);
            }
          }

          @Override
          public void onLoadFailed(@NonNull Exception e) {
            if (isCurrentRequest(toStart)) {
              onLoadFailedInternal(toStart, e);
            }
          }
        });
  } 

就是执行fetcher的loadData方法,fetcher我们上面提到了,是HttpUrlFetcher,我们查看一下:


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

(1)loadDataWithRedirects方法就是进行网络访问,获取图片数据

(2)callback.onDataReady就是将结果返回给上一层

至此,网络图片数据的获取就结束了

三、将获取的数据进行缓存

数据是获取了,但是还没有进行数据缓存的 *** 作,我们继续从SourceGenerator的startNextLoad中进行

  private void startNextLoad(final LoadData toStart) {
    loadData.fetcher.loadData(
        helper.getPriority(),
        new DataCallback() {
          @Override
          public void onDataReady(@Nullable Object data) {
            if (isCurrentRequest(toStart)) {
              onDataReadyInternal(toStart, data);
            }
          }

          @Override
          public void onLoadFailed(@NonNull Exception e) {
            if (isCurrentRequest(toStart)) {
              onLoadFailedInternal(toStart, e);
            }
          }
        });
  } 

onDataReady是数据获取之后的回调方法,data类型为InputStream.class,执行onDataReadyInternal方法

  @SuppressWarnings("WeakerAccess")
  @Synthetic
  void onDataReadyInternal(LoadData loadData, Object data) {
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
    if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      dataToCache = data;
      cb.reschedule();
    } else {
      cb.onDataFetcherReady(
          loadData.sourceKey,
          data,
          loadData.fetcher,
          loadData.fetcher.getDataSource(),
          originalKey);
    }
  }

首先data肯定不是空的,然后判断diskCacheStrategy.isDataCacheable返回值

(1)diskCacheStrategy我们上面说了,是DiskCacheStrategy.AUTOMATIC。

(2)loadData.fetcher是HttpUrlFetcher,getDataSource返回值固定为DataSource.REMOTE

查看isDataCacheable方法
 

        @Override
        public boolean isDataCacheable(DataSource dataSource) {
          return dataSource == DataSource.REMOTE;
        }

很明显,就是true。所以在onDataReadyInternal方法中,执行if中的 *** 作

(1)dataToCache赋值为data,这是要缓存的类对象

(2)调用cb.reschedule,这个cb我们没有关注过,我们进行调用查找,很明显就能直到,cb其实就是DecodeJob

查看DecodeJob的reschedule方法

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

希望大家没有忘记这里,我们之前也调用到了这里,callback为EngineJob,在EngineJob的reschedule方法中,使用线程池执行了DecodeJob的run方法(没印象的小伙伴可以向上翻翻),所以我们又再次回到了DecodeJob的run方法中,然后是runWrapped方法,直接看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);
    }
  }

runReason为SWITCH_TO_SOURCE_SERVICE,所以执行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;
      }
    }
    // We've run out of stages and generators, give up.
    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
      notifyFailed();
    }

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

不废话,直接进入SourceGenerator的startNext方法中

  @Override
  public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }

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

虽然又到了startNext,但是有了不一样的地方,dataToCache不为空了,所以执行cacheData方法。

  private void cacheData(Object dataToCache) {
    long startTime = LogTime.getLogTime();
    try {
      Encoder encoder = helper.getSourceEncoder(dataToCache);
      DataCacheWriter writer =
          new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
      originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
      helper.getDiskCache().put(originalKey, writer);
      ....
    } finally {
      loadData.fetcher.cleanup();
    }

    sourceCacheGenerator =
        new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
  } 

(1)这里要是深究起来,也会比较复杂,我们只要直到一件事就可以了,将资源写入到了磁盘缓存中。第8行的位置,getDiskCache获取的就是磁盘缓存的容器,然后进行了put *** 作

(2)sourceCacheGenerator赋值为DataCacheGenerator,第一个参数我们要关注,是资源的key,传入到了DataCacheGenerator中。

至此,数据被缓存到了磁盘中

四、将数据加入到内存缓存,并且展示到ImageView中

我们回到上面SourceGenerator的startNext方法

  @Override
  public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }

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

此时sourceCacheGenerator为DataCacheGenerator,不为空,然后执行了startNext方法,我们查看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;
        modelLoaders = helper.getModelLoaders(cacheFile);
        modelLoaderIndex = 0;
      }
    }

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

(1)根据缓存的key,从磁盘缓存中拿到了刚刚存入的缓存文件,也就是cacheFile

(2)调用了helper的getModelLoaders方法,获取了modelLoader的列表,看一下getModelLoaders的方法

  List> getModelLoaders(File file)
      throws Registry.NoModelLoaderAvailableException {
    return glideContext.getRegistry().getModelLoaders(file);
  }

根据file获取ModelLoader。这里大家应该很眼熟了把。在SourceGenerator的流程中,有过相似的代码,流程都是一样的,所以我就不再进去寻找了,结果如下:

modelClassdataClassModelLoaderFactoryFetcher
File.classByteBuffer.class

ByteBufferFileLoader

ByteBufferFileLoader.Factory

ByteBufferFetcher
File.classInputStream.classFileLoaderFileLoader.StreamFactoryFileFetcher

(1)之后进入startNext的第二个while,其中获取了第一个ModelLoader,也就是ByteBufferFileLoader,构建了loadData。loadData中的Fetcher我已经在上面贴出来了,是ByteBufferFetcher

(2)ByteBufferFetcher对象调用了loadData,进行了数据的获取

我们直接进入ByteBufferFetcher的loadData方法中查看

    @Override
    public void loadData(
        @NonNull Priority priority, @NonNull DataCallback callback) {
      ByteBuffer result;
      try {
        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;
      }

      callback.onDataReady(result);
    }

result对象类型为ByteBuffer,通过callback的onDataReady方法回到了DataCacheGenerator中,我们看一下

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

很眼熟的代码,我们上面说过,具体的流程我不再赘述,我直接描述一下:

cb是SourceGenerator

SourceGenerator.onDataFetcherReady=>DecodeJob.onDataFetcherReady,我直接看DecodeJob的onDataFetcherReady方法

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

这里的线程没有变化,所以执行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();
    }
  }

第4行,调用了decodeFromData方法,这里又是一波十八弯,实在是弯不动了,我就口述一下吧。

我们从上面的流程知道了,currentData是ByteBuffer类型的,但是我们想在ImageView上展示出来的类型是Drawable(在最一开始说过,transcodeClass类型),所以现将ByteBuffer编码为Bitmap类型,然后再将Bitmap转码为BitmapDrawable。

再次调用notifyEncodeAndRelease方法,进去看看:

  private void notifyEncodeAndRelease(Resource resource, DataSource dataSource) {
    if (resource instanceof Initializable) {
      ((Initializable) resource).initialize();
    }

    Resource result = resource;
    LockedResource lockedResource = null;
    if (deferredEncodeManager.hasResourceToEncode()) {
      lockedResource = LockedResource.obtain(resource);
      result = lockedResource;
    }

    notifyComplete(result, dataSource);

    stage = Stage.ENCODE;
    try {
      if (deferredEncodeManager.hasResourceToEncode()) {
        deferredEncodeManager.encode(diskCacheProvider, options);
      }
    } finally {
      if (lockedResource != null) {
        lockedResource.unlock();
      }
    }
    // Call onEncodeComplete outside the finally block so that it's not called if the encode process
    // throws.
    onEncodeComplete();
  }

调用notifyComplete方法

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

这个callback对象,上面提过,是EngineJob,所以查看EngineJob的onResourceReady方法

  @Override
  public void onResourceReady(Resource resource, DataSource dataSource) {
    synchronized (this) {
      this.resource = resource;
      this.dataSource = dataSource;
    }
    notifyCallbacksOfResult();
  }

查看notifyCallbacksOfResult方法

void notifyCallbacksOfResult() {
    ....
    engineJobListener.onEngineJobComplete(this, localKey, localResource);

    for (final ResourceCallbackAndExecutor entry : copy) {
      entry.executor.execute(new CallResourceReady(entry.cb));
    }
    decrementPendingCallbacks();
}

(1)第3行:将数据存到内存缓存中的活动缓存,感兴趣的同学可以点击去看一下

(2)for循环中的,线程池执行了一个任务,所以我们直接进入CallResourceReady中的run方法查看:

    @Override
    public void run() {
      // Make sure we always acquire the request lock, then the EngineJob lock to avoid deadlock
      // (b/136032534).
      synchronized (cb.getLock()) {
        synchronized (EngineJob.this) {
          if (cbs.contains(cb)) {
            // Acquire for this particular callback.
            engineResource.acquire();
            callCallbackOnResourceReady(cb);
            removeCallback(cb);
          }
          decrementPendingCallbacks();
        }
      }
    }

查看callCallbackOnResourceReady方法

  void callCallbackOnResourceReady(ResourceCallback cb) {
    try {
      cb.onResourceReady(engineResource, dataSource);
    } catch (Throwable t) {
      throw new CallbackException(t);
    }
  }

cb其实是SingleRequest,我们直接进入SingleRequest的onResourceReady方法查看:

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

查看onResourceReady方法

private void onResourceReady(Resource resource, R result, DataSource dataSource) {
    ....

      if (!anyListenerHandledUpdatingTarget) {
        Transition animation = animationFactory.build(dataSource, isFirstResource);
        target.onResourceReady(result, animation);
      }
    } finally {
      isCallingCallbacks = false;
    }

    notifyLoadSuccess();
  }

我们终于看见了target,这个target就是对我们ImageView的一个封装,之后我们就不继续了,无非就是数据设置之类的 *** 作。

五、总结

写了4万字,估计没人看,就当自己的笔记了,我还是总结一下看源码的方法

1.多做笔记

像Glide这种调用栈比较深,比较乱的,我们再看的时候一定要做随手笔记,防止我们看的比较深的时候,会忘记之前的参数是什么类型,什么意思

2.Debug调试

三方可以使用Debug调试的,我们看的时候总是有不确定的时候,Debug一下,看看到底是不是代码走到了这里,参数具体是什么类型

3.反向查找

思路断了的时候,反向查找的效果会比较好。比如:我在看的时候,没有找到数据是怎么放到内存缓存的,这时候可以使用反向查找,看看内存缓存在哪里添加,和自己所看的流程重合了,就OK了

4.多看

源码还是要多看,反复咀嚼

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/719893.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)