Glide加载流程1——缓存加载流程

441 阅读4分钟

入口方法是Enigine.load()

  1. 从内存中加载——loadFromMemory()
  2. 从磁盘或网络加载
public <R> LoadStatus load(/***/) {
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

    EngineKey key =
        keyFactory.buildKey(//***);

    EngineResource<?> memoryResource;
    synchronized (this) {
      memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);

      if (memoryResource == null) {
        return waitForExistingOrStartNewJob(
            //***)
      }
    }
    cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
    return null;
}

内存加载的过程:

  1. 从内存中正在使用的资源中加载
  2. 从内存缓存中加载
private EngineResource<?> loadFromMemory(
      EngineKey key, boolean isMemoryCacheable, long startTime) {
    if (!isMemoryCacheable) {
      return null;
    }
    EngineResource<?> active = loadFromActiveResources(key);
    if (active != null) {
      return active;
    }

    EngineResource<?> cached = loadFromCache(key);
    if (cached != null) {
      return cached;
    }

    return null;
  }

从正在使用的资源中加载:

ActivityResources是一个资源管理类,将当前正在使用的资源进行了保存(用WeakReference持有资源,并保存到Map中)。

  private EngineResource<?> loadFromActiveResources(Key key) {
    EngineResource<?> active = activeResources.get(key);
    if (active != null) {
      active.acquire();
    }

    return active;
  }

从缓存中加载:

从MemoryCache中获取缓存,如果有,则放入给该资源引用计数加1,并放入ActivityResources中。

private EngineResource<?> loadFromCache(Key key) {
    EngineResource<?> cached = getEngineResourceFromCache(key);
    if (cached != null) {
      cached.acquire();
      activeResources.activate(key, cached);
    }
    return cached;
  }

  private EngineResource<?> getEngineResourceFromCache(Key key) {
    Resource<?> cached = cache.remove(key);

    final EngineResource<?> result;
    if (cached == null) {
      result = null;
    } else if (cached instanceof EngineResource) {
      // Save an object allocation if we've cached an EngineResource (the typical case).
      result = (EngineResource<?>) cached;
    } else {
      result =
          new EngineResource<>(
              cached, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ true, key, /*listener=*/ this);
    }
    return result;
  }

如果内存中没有,需要从磁盘缓存或者网络中加载,主要逻辑在waitForExistingOrStartNewJob()中:

  1. 当前是否已有该资源的加载任务,如果有,则添加一个回调,避免重复加载;
  2. 启动一个EngineJob用于管理加载的回调,实际的加载工作在DecodeJob中完成
private <R> LoadStatus waitForExistingOrStartNewJob(/**/) {

    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
      current.addCallback(cb, callbackExecutor);
      return new LoadStatus(cb, current);
    }

    EngineJob<R> engineJob =
        engineJobFactory.build(/**/);

    DecodeJob<R> decodeJob = decodeJobFactory.build(/**/);

    jobs.put(key, engineJob);
    engineJob.addCallback(cb, callbackExecutor);
    engineJob.start(decodeJob);
    return new LoadStatus(cb, engineJob);
  }

可以看下EngineJob.start() 的实现——将DecodeJob放入线程池等待执行:

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

DecodeJob实现了Runnable接口,重点看它实现的run()方法:

  1. 判断是否已取消
  2. 调用runWrapped()方法执行状态转换
  3. 一些异常处理和回调执行
public void run() {
 	//***
    DataFetcher<?> localFetcher = currentFetcher;
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      runWrapped();
    } catch (CallbackException e) {
      //***
      throw e;
    } catch (Throwable t) {
      //***
      if (stage != Stage.ENCODE) {
        throwables.add(t);
        notifyFailed();
      }
      if (!isCancelled) {
        throw t;
      }
      throw t;
    } finally {
      //***
    }
  }

runWrapped() 是状态转换的关键方法,用于处理初始化——加载——解码:

  1. 判断当前状态
  2. 获取资源处理器
  3. 运行资源处理器
  private void runWrapped() {
    switch (runReason) {
      case INITIALIZE:
        stage = getNextStage(Stage.INITIALIZE);
        currentGenerator = getNextGenerator();
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }

状态转换的关系在getNextStage() 方法中(跟磁盘缓存策略有关):

  1. RESOURCE_CACHE——缓存转换后的图片资源
  2. DATA_CACHE——只缓存原始的图片资源
  3. SOURCE——不缓存,只从网络加载
  4. FINISHED——只从缓存加载,状态变成结束;或者从网络加载的下一个状态也是结束
  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:
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
  }

通过判断当前的状态,然后获取当前应该使用的数据获取生成器:

  1. RESOURCE_CACHE对应ResourceCacheGenerator()用于获取缓存的转换后的图片
  2. DATA_CACHE对应DataCacheGenerator()用户获取缓存的原始的图片资源
  3. SOURCE对应SourceGenerator()用于从网络加载图片
  4. 它们都持有了DecodeJob实现的FetcherReadyCallback接口,处理资源加载完成的回调
  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);
    }
  }

DecodeJob实现的FetcherReadyCallback回调:

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

看下RunReason的注释:

private enum RunReason {
    /** The first time we've been submitted. */
    INITIALIZE,
    /** We want to switch from the disk cache service to the source executor. */
    SWITCH_TO_SOURCE_SERVICE,
    /**
     * We retrieved some data on a thread we don't own and want to switch back to our thread to
     * process the data.
     */
    DECODE_DATA,
  }

其中的SWITCH_TO_SOURCE_SERVICE表明是从磁盘缓存转换为数据处理。

其中的callback是EngineJob自己实现了DecodeJob.Callback接口,逻辑是再次执行DecodeJob:

  @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.
    getActiveSourceExecutor().execute(job);
  }

而DecodeJob的run()方法会继续调用runWrapped()方法,因为此时的runReason已变成SWITCH_TO_SOURCE,所以会继续调用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();
    }
  }

可以看到runGenerators()是一个状态机的思路,一级一级往上获取图片资源,状态转换由getNextStage()实现,状态定义在Stage 中:

  /** Where we're trying to decode data from. */
  private enum Stage {
    /** The initial stage. */
    INITIALIZE,
    /** Decode from a cached resource. */
    RESOURCE_CACHE,
    /** Decode from cached source data. */
    DATA_CACHE,
    /** Decode from retrieved source. */
    SOURCE,
    /** Encoding transformed resources after a successful load. */
    ENCODE,
    /** No more viable stages. */
    FINISHED,
  }

所以如果在RESOURCE_CACHE和DATA_CACHE的缓存中找到资源就结束,否则会进行网络请求。