Glide 源码阅览笔记(五)

在榜首篇文章中我简略介绍了Glide实例的创立进程,要点介绍了Glide的内存缓存完结和磁盘的缓存完结:Glide 源码阅览笔记(一)

在第二篇文章中介绍了Glide对生命周期的办理:Glide 源码阅览笔记(二)

在第三篇文章中介绍了 RequestRequestCoordinator,还简略介绍了 Registry 中的核心组件:Glide 源码阅览笔记(三)

第四篇文章中介绍了 Glide 怎样加载内存缓存和磁盘缓存的资源。其间内存缓存又分为存活的内存缓存资源和被缓存的内存缓存资源;磁盘缓存分为 RESOURCE_CACHE 类型(有尺度等参数作为 key)缓存与 DATA_CACHE 类型(从网络中加载的原始缓存数据,无尺度等等信息):Glide 源码阅览笔记(四)

本篇文章持续接着上篇文章中介绍没有磁盘缓存和内存缓存时,怎样加载网络中的数据,以及怎样写入 RESOURCE_CACHEDATA_CACHE 磁盘缓存。别的再讲讲加载使命对 Android 中生命周期的呼应。

加载网络数据和写入磁盘缓存

在前面的文章中介绍过加载缓存时会工作在 DiskCacheExecutor 中履行(也便是 ResourceCacheGeneratorDataCacheGenerator),而加载网络数据时会在 ActiveSourceExecutor 中履行(SourceGenerator)。所以咱们就以 SourceGenerator#startNext() 办法开始剖析:

  @Override
  public boolean startNext() {
    // ...
    while (!started && hasNextModelLoader()) {
      // 找到一个可用的 DataLoader 中的 LoadData 目标
      loadData = helper.getLoadData().get(loadDataListIndex++);
      // 然后经过 LoadData 中最终的输出目标的 Class 目标,然后去查找 Decoder 和 Transcoder,他们都被封装在 LoadPath 中。
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
              || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        // 找到可以用的 LoadPath 目标。
        startNextLoad(loadData);
      }
    }
    return started;
  }

我删除了部分本次逻辑不会用到的代码,后面再持续看。这儿首要去查找可以用的 DataLoader,然后获取到它的 LoadData 目标,然后获取到最终它处理后的目标的 Class 目标。咱们这儿其实便是找到一个网络恳求相关的 DataLoader,咱们输入的目标是 String 类型的地址,然后它的返回目标便是一个 InputStream
然后持续查找可以处理 InputStreamDecoderTranscoder,然后他们被封装在 LoadPath 目标中,然后调用 startNextLoad() 办法:

  private void startNextLoad(final LoadData<?> toStart) {
    loadData.fetcher.loadData(
        helper.getPriority(),
        new DataCallback<Object>() {
          @Override
          public void onDataReady(@Nullable Object data) {
            // 回调 LoadData 加载网络数据成功。
            if (isCurrentRequest(toStart)) {
              onDataReadyInternal(toStart, data);
            }
          }
          @Override
          public void onLoadFailed(@NonNull Exception e) {
            if (isCurrentRequest(toStart)) {
              onLoadFailedInternal(toStart, e);
            }
          }
        });
  }

便是一个简略的异步回调,成功后会调用 onDataReadyInternal() 办法,其实这个 data 便是 InputStream

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

上面的代码分为两种情况,一种是答应 DataCache,一种是不答应,咱们直接看答应缓存的逻辑(不答应缓存更加简略)。它会把 data 保存在 dataToCache 变量中,然后调用 cbreschedule() 办法,这个 cb 其实便是 DecodeJob,这个办法它会再次触发 SourceGenerator#startNext() 办法,这个时分咱们就能持续看之前咱们删除掉的那部分代码了:

  @Override
  public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      try {
        // 履行缓存 DataCache 操作。
        boolean isDataInCache = cacheData(data);
        if (!isDataInCache) {
          return true;
        }
      } catch (IOException e) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
          Log.d(TAG, "Failed to properly rewind or write data to cache", e);
        }
      }
    }
    // 缓存成功后会调用 DataCacheGenerator#startNext() 办法
    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
      return true;
    }
    sourceCacheGenerator = null;
    // ...
    return started;
  }

由于回调成功后 dataToCache 变量就不为空了,然后经过 cacheData() 办法来缓存 DataCache 到本地磁盘。假如缓存成功,会创立一个 DataCacheGenerator (它是和 DecodeJob 中的 DataCacheGenerator 是不同的实例),然后调用其 startNext() 办法,简略来说便是缓存成功后再去从缓存中再去加载一次,然后持续后续的操作。

咱们再来看看 cacheData() 办法的完结:

  private boolean cacheData(Object dataToCache) throws IOException {
    long startTime = LogTime.getLogTime();
    boolean isLoadingFromSourceData = false;
    try {
      // 用 DataRewinder 来封装对应的 data,使其可以重复的读(也便是让 InputStream 可以重复的读)
      DataRewinder<Object> rewinder = helper.getRewinder(dataToCache);
      // 重置 data。
      Object data = rewinder.rewindAndGet();
      // 查找对应的 Encoder
      Encoder<Object> encoder = helper.getSourceEncoder(data);
      // 构建用于写入文件缓存的 DataCacheWriter 目标。
      DataCacheWriter<Object> writer = new DataCacheWriter<>(encoder, data, helper.getOptions());
      // 构建用于缓存的 DataCacheKey
      DataCacheKey newOriginalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
      DiskCache diskCache = helper.getDiskCache();
      // 写入缓存
      diskCache.put(newOriginalKey, writer);
      // 写入后,判别是否现已写入成功
      if (diskCache.get(newOriginalKey) != null) {
        // 写入成功后构建一个 DataCacheGenerator 目标
        originalKey = newOriginalKey;
        sourceCacheGenerator =
            new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
        // We were able to write the data to cache.
        return true;
      } else {
        isLoadingFromSourceData = true;
        // 假如缓存写入失利,就直接回调 DecodeJob。 
        cb.onDataFetcherReady(
            loadData.sourceKey,
            rewinder.rewindAndGet(),
            loadData.fetcher,
            loadData.fetcher.getDataSource(),
            loadData.sourceKey);
      }
      // We failed to write the data to cache.
      return false;
    } finally {
      if (!isLoadingFromSourceData) {
        loadData.fetcher.cleanup();
      }
    }
  }

上面代码的注释我写的很清楚了,就不再赘述了,假如写入本地缓存成功,会创立 DataCacheGenerator,前面咱们提到会调用它的 startNext() 办法,也便是会触发 DataCacheGenerator 去加载方才写入的缓存,DataCacheGenerator 我在上篇文章中现已介绍过了,不知道的同学翻翻前面的文章。
加载成功后会调用 SourceGenerator#onDataFetcherReady() 办法:

  @Override
  public void onDataFetcherReady(
      Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
    cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
  }

然后持续回调 DecodeJob#onDataFetcherReady() 办法:

  @Override
  public void onDataFetcherReady(
      Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;
    this.currentData = data;
    this.currentFetcher = fetcher;
    this.currentDataSource = dataSource;
    this.currentAttemptingKey = attemptedKey;
    this.isLoadingFromAlternateCacheKey = sourceKey != decodeHelper.getCacheKeys().get(0);
    if (Thread.currentThread() != currentThread) {
      reschedule(RunReason.DECODE_DATA);
    } else {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        decodeFromRetrievedData();
      } finally {
        GlideTrace.endSection();
      }
    }
  }

上面的办法处理也十分简略将回调的各种数据保存在成员变量中,咱们这儿没有切线程,所以接着调用 decodeFromRetrievedData()

  private void decodeFromRetrievedData() {
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logWithTimeAndKey(
          "Retrieved data",
          startFetchTime,
          "data: "
              + currentData
              + ", cache key: "
              + currentSourceKey
              + ", fetcher: "
              + currentFetcher);
    }
    Resource<R> resource = null;
    try {
      // 解码
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
      // 解码成功
      notifyEncodeAndRelease(resource, currentDataSource, isLoadingFromAlternateCacheKey);
    } else {
      runGenerators();
    }
  }

经过调用 decodeFromData() 办法来完结解码,解码成功后调用 notifyEncodeAndRelease() 办法。

  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);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Decoded result " + result, startTime);
      }
      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);
  }

获取到对应的 LoadPath,然后持续调用 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();
    }
  }

这儿持续调用 LoadPath#load() 来完结解码。这儿其实有两个进程,一个是 Decoder 的解码进程,然后是 TranscoderDecoder 的成果转换成 Target 可以渲染的类型。其间 DecodeCallback 可以阻拦处理 Decoder 返回的成果。

    @NonNull
    @Override
    public Resource<Z> onResourceDecoded(@NonNull Resource<Z> decoded) {
      return DecodeJob.this.onResourceDecoded(dataSource, decoded);
    }

咱们看到又调用了 DecodeJob#onResourceDecoded() 办法。这个办法里边就要来处理 RESOURCE_DISK_CACHE 了。

  @Synthetic
  @NonNull
  <Z> Resource<Z> onResourceDecoded(DataSource dataSource, @NonNull Resource<Z> decoded) {
    @SuppressWarnings("unchecked")
    Class<Z> resourceSubClass = (Class<Z>) decoded.get().getClass();
    Transformation<Z> appliedTransformation = null;
    Resource<Z> transformed = decoded;
    if (dataSource != DataSource.RESOURCE_DISK_CACHE) {
      // 经过 Transformation 对尺度和 ScaleType 的处理。
      appliedTransformation = decodeHelper.getTransformation(resourceSubClass);
      transformed = appliedTransformation.transform(glideContext, decoded, width, height);
    }
    // TODO: Make this the responsibility of the Transformation.
    if (!decoded.equals(transformed)) {
      decoded.recycle();
    }
    final EncodeStrategy encodeStrategy;
    final ResourceEncoder<Z> encoder;
    // 判别是否答应 Resource Encoder
    if (decodeHelper.isResourceEncoderAvailable(transformed)) {
      // 查找对应的 Encoder
      encoder = decodeHelper.getResultEncoder(transformed);
      // 获取对应的 EncodeStrategy
      encodeStrategy = encoder.getEncodeStrategy(options);
    } else {
      encoder = null;
      encodeStrategy = EncodeStrategy.NONE;
    }
    Resource<Z> result = transformed;
    boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey);
    // 判别是否答应 Resource Cache.
    if (diskCacheStrategy.isResourceCacheable(
        isFromAlternateCacheKey, dataSource, encodeStrategy)) {
      if (encoder == null) {
        throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass());
      }
      final Key key;
      // 根据 EncodeStrategy 来选择不同的缓存 Key
      switch (encodeStrategy) {
        case SOURCE:
          key = new DataCacheKey(currentSourceKey, signature);
          break;
        case TRANSFORMED:
          key =
              new ResourceCacheKey(
                  decodeHelper.getArrayPool(),
                  currentSourceKey,
                  signature,
                  width,
                  height,
                  appliedTransformation,
                  resourceSubClass,
                  options);
          break;
        default:
          throw new IllegalArgumentException("Unknown strategy: " + encodeStrategy);
      }
      LockedResource<Z> lockedResult = LockedResource.obtain(transformed);
      // 初始化 deferredEncodeManager。
      deferredEncodeManager.init(key, encoder, lockedResult);
      result = lockedResult;
    }
    return result;
  }

上面有一个点需求留意便是假如数据来源是 RESOURCE_DISK_CACHE 那么就不需求裁剪操作,因为 RESOURCE_DISK_CACHE 缓存中的数据现已做过裁剪操作了。假如需求处理 RESOURCE_DISK_CACHE 那么就会初始化 deferredEncodeManager

咱们再来看看解码完结后 notifyEncodeAndRelease() 办法是怎样处理的:

  private void notifyEncodeAndRelease(
      Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
    GlideTrace.beginSection("DecodeJob.notifyEncodeAndRelease");
    try {
      // ...
      try {
        if (deferredEncodeManager.hasResourceToEncode()) {
          deferredEncodeManager.encode(diskCacheProvider, options);
        }
      } finally {
        if (lockedResource != null) {
          lockedResource.unlock();
        }
      }
      // ...
    } finally {
      GlideTrace.endSection();
    }
  }

咱们看到它会调用 DeferredEncodeManager#encode() 办法:

    void encode(DiskCacheProvider diskCacheProvider, Options options) {
      GlideTrace.beginSection("DecodeJob.encode");
      try {
        diskCacheProvider
            .getDiskCache()
            .put(key, new DataCacheWriter<>(encoder, toEncode, options));
      } finally {
        toEncode.unlock();
        GlideTrace.endSection();
      }
    }

也没什么好说的了,直接就写入到磁盘缓存中了。

咱们再看看缓存战略的接口:

  // 是否可以写入 DataCache 缓存
  public abstract boolean isDataCacheable(DataSource dataSource);
  // 是否可以写入 ResourceCache 缓存
  public abstract boolean isResourceCacheable(
      boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy);
  // 是否可以读取 ResourceCache 缓存
  public abstract boolean decodeCachedResource();
  // 是否可以读取 DataCache 缓存
  public abstract boolean decodeCachedData();

Glide 完结了以下几种:

  • AUTOMATIC (默许战略)
  public static final DiskCacheStrategy AUTOMATIC =
      new DiskCacheStrategy() {
        @Override
        public boolean isDataCacheable(DataSource dataSource) {
          return dataSource == DataSource.REMOTE;
        }
        @Override
        public boolean isResourceCacheable(
            boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
          return ((isFromAlternateCacheKey && dataSource == DataSource.DATA_DISK_CACHE)
                  || dataSource == DataSource.LOCAL)
              && encodeStrategy == EncodeStrategy.TRANSFORMED;
        }
        @Override
        public boolean decodeCachedResource() {
          return true;
        }
        @Override
        public boolean decodeCachedData() {
          return true;
        }
      };
  • ALL
  public static final DiskCacheStrategy ALL =
      new DiskCacheStrategy() {
        @Override
        public boolean isDataCacheable(DataSource dataSource) {
          return dataSource == DataSource.REMOTE;
        }
        @Override
        public boolean isResourceCacheable(
            boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
          return dataSource != DataSource.RESOURCE_DISK_CACHE
              && dataSource != DataSource.MEMORY_CACHE;
        }
        @Override
        public boolean decodeCachedResource() {
          return true;
        }
        @Override
        public boolean decodeCachedData() {
          return true;
        }
      };
  • NONE
  public static final DiskCacheStrategy NONE =
      new DiskCacheStrategy() {
        @Override
        public boolean isDataCacheable(DataSource dataSource) {
          return false;
        }
        @Override
        public boolean isResourceCacheable(
            boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
          return false;
        }
        @Override
        public boolean decodeCachedResource() {
          return false;
        }
        @Override
        public boolean decodeCachedData() {
          return false;
        }
      };
  • DATA
  public static final DiskCacheStrategy DATA =
      new DiskCacheStrategy() {
        @Override
        public boolean isDataCacheable(DataSource dataSource) {
          return dataSource != DataSource.DATA_DISK_CACHE && dataSource != DataSource.MEMORY_CACHE;
        }
        @Override
        public boolean isResourceCacheable(
            boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
          return false;
        }
        @Override
        public boolean decodeCachedResource() {
          return false;
        }
        @Override
        public boolean decodeCachedData() {
          return true;
        }
      };
  • RESOURCE
  public static final DiskCacheStrategy RESOURCE =
      new DiskCacheStrategy() {
        @Override
        public boolean isDataCacheable(DataSource dataSource) {
          return false;
        }
        @Override
        public boolean isResourceCacheable(
            boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
          return dataSource != DataSource.RESOURCE_DISK_CACHE
              && dataSource != DataSource.MEMORY_CACHE;
        }
        @Override
        public boolean decodeCachedResource() {
          return true;
        }
        @Override
        public boolean decodeCachedData() {
          return false;
        }
      };

生命周期对 Request 的影响

在第二篇文章中我介绍了 GlideAndroid 生命周期的处理,Glide 会监听 FramgentActivityFragmentonStart()onStop()onDestroy() 三个生命周期。这些生命周期时间会下发至 RequestManager,然后 RequestManager 再去操控它的 Request

onStart()

onStart() 生命周期中主要是重新开始 onStop() 生命周期中被暂停的 Request。咱们直接看看 RequestManager#onStart() 办法源码:

  @Override
  public synchronized void onStart() {
    // 康复暂停的 Request。
    resumeRequests();
    // 回调 Target 的 onStart() 办法。
    targetTracker.onStart();
  }

咱们首要看看 resumeRequests() 办法中是怎样暂停 Request 的:

  public synchronized void resumeRequests() {
    requestTracker.resumeRequests();
  }

持续追寻 RequestTracker#resumeRequests() 办法的完结:

  public void resumeRequests() {
    // 更新暂停状况
    isPaused = false;
    // 遍历一切的 Request
    for (Request request : Util.getSnapshot(requests)) {
      // 假如 Request 没有在 Running 状况,调用对应的 begin() 办法
      if (!request.isComplete() && !request.isRunning()) {
        request.begin();
      }
    }
    // 铲除暂停的 Request 的列表
    pendingRequests.clear();
  }

上面代码十分简略,遍历一切的暂停的 Request 然后调用其对应的 begin() 办法康复恳求。

咱们再来看看 TargetTracker#onStart() 办法的源码:

  @Override
  public void onStart() {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onStart();
    }
  }

朴实无华的代码,遍历一切的 Target 然后调用其 onStart() 办法。

咱们来看看 ImageViewTarget#onStart() 办法是怎样处理的:

  @Override
  public void onStart() {
    if (animatable != null) {
      animatable.start();
    }
  }

其实也便是康复没有履行完结的动画

onStop()

onStop() 生命周期中会暂停没有完结的 Request,虽然说是暂停,其实并不是真实的暂停,并且网络调用也并不能暂停,Glide 中所谓的暂停,其实便是暂停处理回调成功后的成果,等到下次 onStart() 后再持续处理。咱们持续看看 RequestManager#onStop() 的完结:

  @Override
  public synchronized void onStop() {
    // 调用 Target 的 onStop() 生命周期
    targetTracker.onStop();
    if (clearOnStop) {
      // 铲除没有完结的 Request
      clearRequests();
    } else {
      // 暂停没有完结的 Request
      pauseRequests();
    }
  }

首要经过 TargetTracker#onStop() 办法告诉 TargetonStop() 生命周期;后续的代码分为两种情况:经过 pauseRequests() 办法暂停没有完结的 Request(这也是默许的处理方式);经过 clearRequests() 办法铲除没有完结的 Request(咱们讲 onDestroy() 的时分再讲这个办法)。

咱们看看 ImageViewTarget#onStop() 怎样处理 onStop() 生命周期的:

  @Override
  public void onStop() {
    if (animatable != null) {
      animatable.stop();
    }
  }

onStart() 生命周期对应,便是中止正在履行的动画。

持续看看 pauseRequests() 办法是怎样暂停 Request 的:

public synchronized void pauseRequests() {
   requestTracker.pauseRequests();  
}

持续追寻 RequestTracker#pauseRequsts() 办法:

  public void pauseRequests() {
    isPaused = true;
    for (Request request : Util.getSnapshot(requests)) {
      if (request.isRunning()) {
        request.pause();
        pendingRequests.add(request);
      }
    }
  }

遍历一切的 Request,假如正在运转,那么调用 Request#pause() 办法,一起将对应的 Request 增加到 pendingRequests 列表中。
咱们在前面的文章中知道,Request 真实的完结类是 SingleRequest,咱们来看看 SingleRequest#pause() 是怎样完结的:

  @Override
  public void pause() {
    synchronized (requestLock) {
      if (isRunning()) {
        clear();
      }
    }
  }

持续调用对应的 clear() 办法:

  @Override
  public void clear() {
    Resource<R> toRelease = null;
    synchronized (requestLock) {
      assertNotCallingCallbacks();
      stateVerifier.throwIfRecycled();
      if (status == Status.CLEARED) {
        return;
      }
      cancel();
      // Resource must be released before canNotifyStatusChanged is called.
      if (resource != null) {
        toRelease = resource;
        resource = null;
      }
      if (canNotifyCleared()) {
        target.onLoadCleared(getPlaceholderDrawable());
      }
      GlideTrace.endSectionAsync(TAG, cookie);
      status = Status.CLEARED;
    }
    if (toRelease != null) {
      engine.release(toRelease);
    }
  }

上面代码会持续调用 cancel() 办法,然后将状况更新为 CLEARED,还或许告诉 Target#onLoadCleared() 办法,这儿的参数用的是 PlaceholderDrawable()。假如当前的 Resource 不为空,还会将其开释。

咱们来看看 cancel() 办法的完结:

  private void cancel() {
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    target.removeCallback(this);
    if (loadStatus != null) {
      loadStatus.cancel();
      loadStatus = null;
    }
  }

首要将 TargetSize 回调从 Target 中移除,然后调用 LoadStatus#cancel() 办法。加载 TargetSize 在第四篇文章中说过,这个 LoadStatusEngine#load() 办法返回的,用它来操控加载进程中使命,在第四篇文章中也说过。

    public void cancel() {
      synchronized (Engine.this) {
        engineJob.removeCallback(cb);
      }
    }

其实便是简略将恳求成功/失利的回调从 EngineJob 中移除,或许你忘记了这个 Callback 是什么时分增加进去的,在第四篇文章中讲过,咱们再回想回想 SingleRequest#onSizeReady() 办法:

  @Override
  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#load() 办法传递的 this 其实便是上面被移除的 Callback。所以 Glide 中的暂停其实便是将 SingleRequest 中的 Callback 移除,这会影响后续的 Target 的渲染相关的 UI 流程,可是并不会影响 Engine 中对内存缓存,磁盘缓存的逻辑处理,所以当下次 SingleRequest 康复时,它就可以直接从内存缓存中或者磁盘缓存中快速加载,而不用再恳求网络。

onDestroy()

onDestroy() 也表明 RequestManager 到了生命末期,它和它其间的 RequestTarget 也都需求被毁掉并且都不可以再康复。

  @Override
  public synchronized void onDestroy() {
    // 对 Target 回调 onDestroy 生命周期
    targetTracker.onDestroy();
    // 移除 Target 中引用的 Request
    clearRequests();
    // 铲除一切的 Request
    requestTracker.clearRequests();
    // 移除 RequestManager 对生命周期的监听
    lifecycle.removeListener(this);
    // 移除 ConnectiveityMonitor 对生命周期的监听
    lifecycle.removeListener(connectivityMonitor);
    Util.removeCallbacksOnUiThread(addSelfToLifecycle);
    // 告诉 Glide 当前 RquestManager 被移除。
    glide.unregisterRequestManager(this);
  }

ImageViewTarget 中是把 Request 存放在 ImageViewTag 中,前面有提到过,我这儿再烦琐下。然后咱们再看看 RequestTracker#clearRequests() 办法是怎样铲除 Request 的(留意区别和 pauseRequests() 办法处理的方式):

  public void clearRequests() {
    for (Request request : Util.getSnapshot(requests)) {
      // It's unsafe to recycle the Request here because we don't know who might else have a
      // reference to it.
      clearAndRemove(request);
    }
    pendingRequests.clear();
  }

遍历一切的 Request 并调用 clearAndRemove() 办法,一起清空 pendingRequests 中暂停的 Request

咱们看看 clearAndRemove() 办法的完结:

  public boolean clearAndRemove(@Nullable Request request) {
    if (request == null) {
      // If the Request is null, the request is already cleared and we don't need to search further
      // for its owner.
      return true;
    }
    boolean isOwnedByUs = requests.remove(request);
    // Avoid short circuiting.
    isOwnedByUs = pendingRequests.remove(request) || isOwnedByUs;
    if (isOwnedByUs) {
      request.clear();
    }
    return isOwnedByUs;
  }

上面会将一切 RequestrequestspendingRequests 中移除,一起调用 Request#clear() 办法(这个办法咱们上面现已剖析过了),而 resumeRequests() 办法中并不会将 Requestreuqests 中移除,并且会将 Request 增加到 pendingRequests 中去,供下次康复时再调用对应的 begin() 办法。

最终

本篇文章介绍了 Glide 怎样加载网络恳求的数据和怎样写入磁盘缓存(包含 ResourceCacheDataCache );还介绍了 RequestManager 具体怎样处理不同的 Android 生命周期。