安卓系列之第三方库Glide缓存机制篇

206 阅读10分钟

两种缓存

  1. 内存缓存
    a.活动资源 (Active Resources):正在使用的图片。
    b.内存缓存 (Memory cache):内存缓存中的图片。
  2. 磁盘缓存
    a.资源类型(Resource):磁盘缓存中转换过后的图片。
    b.数据来源 (Data):磁盘缓存中的原始图片。

缓存策略

第一次从网络上加载图片后,将它缓存到设备磁盘和内存中,其他地方或者下次使用这张图片的时候就不从网络上请求了。下次需要加载这张图片时,首先从内存缓存中找,如果没有就去磁盘缓存中查找,都没有才从网络上加载。

缓存Key

缓存功能必然要有一个唯一的缓存Key用来存储和查找对应的缓存数据。看一下Engine类的load()方法。

    /**
     * 1.Engine 类
     */
  public <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      boolean isScaleOnlyOrNoTransform,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean useAnimationPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb,
      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);
      }
    }

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

我们再看EngineKeyFactory类。

    /**
     * 2.EngineKeyFactory
     * */
class EngineKeyFactory {

  @SuppressWarnings("rawtypes")
  EngineKey buildKey(
      Object model,
      Key signature,
      int width,
      int height,
      Map<Class<?>, Transformation<?>> transformations,
      Class<?> resourceClass,
      Class<?> transcodeClass,
      Options options) {
      //返回一个新的缓存Key
    return new EngineKey(
        model, signature, width, height, transformations, resourceClass, transcodeClass, options);
  }
}

我们再看EngineKey类,通过重写equals()与hashCode()方法来保证缓存Key的唯一性。

class EngineKey implements Key {
  private final Object model;
  private final int width;
  private final int height;
  private final Class<?> resourceClass;
  private final Class<?> transcodeClass;
  private final Key signature;
  private final Map<Class<?>, Transformation<?>> transformations;
  private final Options options;
  private int hashCode;

  EngineKey(
      Object model,
      Key signature,
      int width,
      int height,
      Map<Class<?>, Transformation<?>> transformations,
      Class<?> resourceClass,
      Class<?> transcodeClass,
      Options options) {
    this.model = Preconditions.checkNotNull(model);
    this.signature = Preconditions.checkNotNull(signature, "Signature must not be null");
    this.width = width;
    this.height = height;
    this.transformations = Preconditions.checkNotNull(transformations);
    this.resourceClass =
        Preconditions.checkNotNull(resourceClass, "Resource class must not be null");
    this.transcodeClass =
        Preconditions.checkNotNull(transcodeClass, "Transcode class must not be null");
    this.options = Preconditions.checkNotNull(options);
  }

  @Override
  public boolean equals(Object o) {
    if (o instanceof EngineKey) {
      EngineKey other = (EngineKey) o;
      return model.equals(other.model)
          && signature.equals(other.signature)
          && height == other.height
          && width == other.width
          && transformations.equals(other.transformations)
          && resourceClass.equals(other.resourceClass)
          && transcodeClass.equals(other.transcodeClass)
          && options.equals(other.options);
    }
    return false;
  }

  @Override
  public int hashCode() {
    if (hashCode == 0) {
      hashCode = model.hashCode();
      hashCode = 31 * hashCode + signature.hashCode();
      hashCode = 31 * hashCode + width;
      hashCode = 31 * hashCode + height;
      hashCode = 31 * hashCode + transformations.hashCode();
      hashCode = 31 * hashCode + resourceClass.hashCode();
      hashCode = 31 * hashCode + transcodeClass.hashCode();
      hashCode = 31 * hashCode + options.hashCode();
    }
    return hashCode;
  }

  @Override
  public String toString() {...}

  @Override
  public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
    throw new UnsupportedOperationException();
  }

内存缓存

在内存缓存中,我们需要记住两个内容,一个叫活动资源,一个叫内存缓存。我们从load()方法开始讲解。

public <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      boolean isScaleOnlyOrNoTransform,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean useAnimationPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb,
      Executor callbackExecutor) {
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
    
    EngineKey key =
        keyFactory.buildKey(
            model,
            signature,
            width,
            height,
            transformations,
            resourceClass,
            transcodeClass,
            options);

    EngineResource<?> memoryResource;
    synchronized (this) {
    //根据缓存Key从内存中获取缓存
      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;
  }

再看loadFromMemory方法。

  @Nullable
  private EngineResource<?> loadFromMemory(
      EngineKey key, boolean isMemoryCacheable, long startTime) {
    //若不可以内存缓存,直接返回null
    if (!isMemoryCacheable) {
      return null;
    }
    //从(活动资源)ActiveResources中加载缓存数据。
    EngineResource<?> active = loadFromActiveResources(key);
    //如果有活动资源,则直接返回
    if (active != null) {
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return active;
    }
    //若活动资源没有,则从内存缓存中加载缓存数据。
    EngineResource<?> cached = loadFromCache(key);
    if (cached != null) {
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return cached;
    }

    return null;
  }

再看loadFromActiveResources方法。

  @Nullable
  private EngineResource<?> loadFromActiveResources(Key key) {
    //根据Key去获取活动资源
    EngineResource<?> active = activeResources.get(key);
    //若资源不为null,执行acquire()方法
    if (active != null) {
      active.acquire();
    }
    //返回活动资源
    return active;
  }

再看ActiveResources类的get()方法。

  @Nullable
  synchronized EngineResource<?> get(Key key) {
    //弱引用的haspMap,获取ResourceWeakReference
    ResourceWeakReference activeRef = activeEngineResources.get(key);
    if (activeRef == null) {
      return null;
    }
    //从弱引用中获取活动资源,得到EngineResource
    EngineResource<?> active = activeRef.get();
    //若资源为空,则回收activeRef
    if (active == null) {
      cleanupActiveReference(activeRef);
    }
    return active;
  }

再看EngineResource类的acquire()方法。

  synchronized void acquire() {
    if (isRecycled) {
      throw new IllegalStateException("Cannot acquire a recycled resource");
    }
    //计数加1,用来记录图片被引用的次数
    ++acquired;
  }

这个时候如果活动资源有数据,就已经取到了缓存。若此时活动资源没有数据,则需要去内存缓存中去取。即从loadFromCache方法开始。我们再看一下这个方法。

  private EngineResource<?> loadFromCache(Key key) {
    //获取内存缓存
    EngineResource<?> cached = getEngineResourceFromCache(key);
    if (cached != null) {
      //计数+1,用来记录图片被引用的次数。
      cached.acquire();
      //将内存中获取的缓存数据缓存到弱引用的HashMap中,这个时候就是将内存缓存中的缓存放到活动资源中。
      activeResources.activate(key, cached);
    }
    return cached;
  }

再看一下getEngineResourceFromCache()方法。

  private EngineResource<?> getEngineResourceFromCache(Key key) {
    //remove()操作就是移除缓存的同时获取该缓存(获取内存缓存)
    Resource<?> cached = cache.remove(key);

    final EngineResource<?> result;
    if (cached == null) {
      result = null;
    } else if (cached instanceof EngineResource) {
      result = (EngineResource<?>) cached;
    } else {
      result =
          new EngineResource<>(
              cached, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ true, key, /*listener=*/ this);
    }
    return result;
  }
  

从上面的方法可以知道活动资源里的缓存怎么来的,就是内存缓存中取了缓存资源后存到了活动资源。那么内存缓存中的缓存是怎么来的?刚才我们提到活动资源在获取的时候有个+1的计数操作,看一下活动资源释放的时候是怎么样的呢?看下EngineResource类的release()方法。

  void release() {
    boolean release = false;
    synchronized (this) {
      //如果计数值<= 0,则证明这个资源没有地方调用
      if (acquired <= 0) {
        throw new IllegalStateException("Cannot release a recycled or not yet acquired resource");
      }
      //释放一次,计数减-1,若==0,则证明没有地方用了,需要回收了
      if (--acquired == 0) {
        release = true;
      }
    }
    //如果活动资源需要释放了,则有个监听方法
    if (release) {
      listener.onResourceReleased(key, this);
    }
  }

再看Engine类中的onResourceReleased()方法。

  @Override
  public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
    //根据cacheKey活动资源的HashMap中删除
    activeResources.deactivate(cacheKey);
    //若可以缓存,则缓存到内存缓存中,
    if (resource.isMemoryCacheable()) {
      //MemoryCache cache
      cache.put(cacheKey, resource);
    } else {
      resourceRecycler.recycle(resource, /*forceNextFrame=*/ false);
    }
  }

从这可以看出来,内存缓存的数据是从活动资源释放的时候存储起来的。

总结:

  1. 活动资源的流程:从活动资源(hashMap)中找,如有则计数+1,释放资源时计数-1,若计数为0则缓存到内存缓存中,同时在活动资源中删除。
  2. 内存缓存的流程:根据Key从内存缓存中删除的同时找出来,然后将内存缓存中获取的缓存资源缓存到活动资源的弱引用的HashMap中。

问题

  1. 活动资源的内容哪里来的?
    答案:首次:从网络请求中返回的数据。
  2. 为啥要用一个弱引用的HashMap?
    答案:(1)提高访问效率。HashMap的访问速度是要比LinkedHashMap快;(2)防止内存泄漏。
  • 强引用:直接的对象引用。
  • 软引用:当一个对象只有软引用存在时,系统内存不足时此对象会被gc回收。
  • 弱引用:当一个对象只有弱引用存在时, 此对象会随时被gc回收。

磁盘缓存

在磁盘缓存中,我们需要记住两个名词,叫资源类型和数据来源。

磁盘缓存设置

  1. ALL:既缓存原始图片,也缓存转换过后的图片。
  2. NONE:不缓存任何内容。
  3. DATA:只缓存原始图片。
  4. RESOURCE:只缓存转换过后的图片。
  5. AUTOMATIC:默认策略,它会尝试对本地和远程图片使用最佳的策略。如果是远程图片,则只缓存原始图片;如果是本地图片,那么只缓存转换过后的图片。

缓存算法

LRU(Least Recently Used),即最近最少使用算法。核心思想是当缓存满时,会优先淘汰那些最近最少使用的缓存对象。采用 LRU算法的缓存有两种:LruCache和DiskLruCache。内部算法原理是采用一个LinkedHashMap(有序存储key-value)以强引用的方式存储外界的缓存对象,其提供了get()和put()方法来完成缓存的获取和添加的操作。当缓存满时,会移除较早使用的缓存对象,然后再添加新的缓存对象。

资源类型(Resource)

如何获取缓存,先看DecodeJob这个类。

private void runWrapped() {
    switch (runReason) {
      case INITIALIZE:
        //1.获取资源状态
        stage = getNextStage(Stage.INITIALIZE);
        //2.根据资源状态获取资源执行器
        currentGenerator = getNextGenerator();
        //3.执行
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }
  
  //获取资源状态Stage
  //根据当前用户设置的缓存机制可以得到diskCacheStrategy.decodeCachedResource()和diskCacheStrategy.decodeCachedData()的值,在DiskCacheStrategy类中可以看到具体返回值。
  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);
    }
  }
  
  //根据Stage获取资源执行器
  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);
    }
  }
  
  //当前的执行器执行,即currentGenerator.startNext()方法
  private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    while (!isCancelled
        && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      //走下一个Stage和执行器
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

      if (stage == Stage.SOURCE) {
        reschedule();
        return;
      }
    }
    
    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
      notifyFailed();
    }

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

若配置的是Resource,则执行器是ResourceCacheGenerator,然后看一下这个执行器的startNext()的具体内容。

  @Override
  public boolean startNext() {
    ...
      //构建缓存Key
      currentKey =
          new ResourceCacheKey( // NOPMD AvoidInstantiatingObjectsInLoops
              helper.getArrayPool(),
              sourceId,
              helper.getSignature(),
              helper.getWidth(),
              helper.getHeight(),
              transformation,
              resourceClass,
              helper.getOptions());
      //根据缓存Key去获取缓存文件,获取的是缓存文件
      cacheFile = helper.getDiskCache().get(currentKey);
      if (cacheFile != null) {
        sourceKey = sourceId;
        modelLoaders = helper.getModelLoaders(cacheFile);
        modelLoaderIndex = 0;
      }
    }

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
      loadData =
          modelLoader.buildLoadData(
              cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
      if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
        started = true;
        //对缓存文件进行处理
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }

    return started;
  }

ByteBufferFileLoader类中的loadData()方法。

    @Override
    public void loadData(
        @NonNull Priority priority, @NonNull DataCallback<? super ByteBuffer> callback) {
      ByteBuffer result;
      try {
        //将缓存文件转换成ByteBuffer
        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;
      }
      //成功则将ByteBuffer返回,最终回调到DecodeJob的onDataFetcherReady()方法中
      callback.onDataReady(result);
    }

到此,获取资源类型的缓存结束。然后看一下如何存储的。刚才说到DecodeJob类,看一下里面的notifyEncodeAndRelease()方法。

  //解码完成了通知下去的步骤
  private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
    if (resource instanceof Initializable) {
      ((Initializable) resource).initialize();
    }

    Resource<R> result = resource;
    LockedResource<R> 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();
      }
    }
    onEncodeComplete();
  }
    
      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();
      }
    }

总结

  1. 资源类型的获取流程:先初始化资源状态为INITIALIZE,然后根据设置的磁盘缓存策略得到资源状态Stage,根据资源状态Stage获取到资源执行器,再执行。执行执行器,先构建缓存Key,根据缓存Key去寻找缓存文件,若有则处理缓存文件为ByteBuffer,返回给DecodeJob进行展示等操作。
  2. 资源类型的存储流程:第一次加载的时候在SourceGenerator的startNext()方法中请求到数据,然后解码完成,最后再存储缓存。

数据来源(Data)

如何获取缓存,先看DecodeJob这个类。

private void runWrapped() {
    switch (runReason) {
      case INITIALIZE:
        //1.获取资源状态
        stage = getNextStage(Stage.INITIALIZE);
        //2.根据资源状态获取资源执行器
        currentGenerator = getNextGenerator();
        //3.执行
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }
  
  //获取资源状态Stage
  //根据当前用户设置的缓存机制可以得到diskCacheStrategy.decodeCachedResource()和diskCacheStrategy.decodeCachedData()的值,在DiskCacheStrategy类中可以看到具体返回值。
  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);
    }
  }
  
  //根据Stage获取资源执行器
  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);
    }
  }
  
  //当前的执行器执行,即currentGenerator.startNext()方法
  private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    while (!isCancelled
        && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      //走下一个Stage和执行器
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

      if (stage == Stage.SOURCE) {
        reschedule();
        return;
      }
    }
    
    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
      notifyFailed();
    }

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

若配置的是Data,则执行器是DataCacheGenerator,然后看一下这个执行器的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
      Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
      //根据缓存Key去获取缓存文件
      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<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
      loadData =
          modelLoader.buildLoadData(
              cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
      if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
        started = true;
        //加工缓存文件
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

ByteBufferFileLoader类中的loadData()方法。

    @Override
    public void loadData(
        @NonNull Priority priority, @NonNull DataCallback<? super ByteBuffer> callback) {
      ByteBuffer result;
      try {
        //将缓存文件转换成ByteBuffer
        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;
      }
      //成功则将ByteBuffer返回,最终回调到DecodeJob的onDataFetcherReady()方法中
      callback.onDataReady(result);
    }

到此,获取数据来源的缓存结束。然后看一下如何存储的。看SourceGenerator类中的onDataReadyInternal()方法,这个方法是请求网络得到数据的时候。

  @Synthetic
  void onDataReadyInternal(LoadData<?> loadData, Object data) {
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
    if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      //对即将需要缓存的数据进行赋值
      dataToCache = data;
      // We might be being called back on someone else's thread. Before doing anything, we should
      // reschedule to get back onto Glide's thread.
      //回调
      cb.reschedule();
    } else {
      cb.onDataFetcherReady(
          loadData.sourceKey,
          data,
          loadData.fetcher,
          loadData.fetcher.getDataSource(),
          originalKey);
    }
  }

然后看一下EngineJob的reschedule()方法。

    @Override
  public void reschedule(DecodeJob<?> job) {
    // Even if the job is cancelled here, it still needs to be scheduled so that it can clean itself
    // up.
    //用线程池执行了DecodeJob,然后回到了SourceGenerator的startNext()方法
    getActiveSourceExecutor().execute(job);
  }

看一下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;
  }
  
    //存储数据方法
    private void cacheData(Object dataToCache) {
    long startTime = LogTime.getLogTime();
    try {
      Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
      DataCacheWriter<Object> writer =
          new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
      //构建缓存Key
      originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
      //存储缓存文件
      helper.getDiskCache().put(originalKey, writer);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(
            TAG,
            "Finished encoding source to cache"
                + ", key: "
                + originalKey
                + ", data: "
                + dataToCache
                + ", encoder: "
                + encoder
                + ", duration: "
                + LogTime.getElapsedMillis(startTime));
      }
    } finally {
      loadData.fetcher.cleanup();
    }

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

总结

  1. 原始数据的获取流程:先初始化资源状态为INITIALIZE,然后根据设置的磁盘缓存策略得到资源状态Stage,根据资源状态Stage获取到资源执行器,再执行。执行执行器,先构建缓存Key,根据缓存Key去寻找缓存文件,若有则处理缓存文件为ByteBuffer,返回给DecodeJob进行展示等操作。
  2. 原始数据的存储流程:网络请求结束得到数据时,在SourceGenerator的startNext()方法中构建原始Key,存储原始图片。

若帅哥美女对该系列文章感兴趣,可微信搜索公众号(木子闲集)关注更多更新文章哦,谢谢~