Glide源码解析-四级缓存

Glide是一个优秀的图片加载框架,支持多种数据源,功能强大,性能高。如图所示:

使用步骤

1.在build.gradle中添加glide引用

implementation 'com.github.bumptech.glide:glide:4.12.0'

2.使用glide加载图片

Glide.with(this).load(BASE_PIC_URL).into(img_user)

源码缓存分析

LruCache算法

Glide四级缓存中使用了LruCache最近最少使用算法。其内部使用了LinkedHashMap存储数据,并默认支持排序访问。其工作原理如下:

假设当前LruCache的容量为4,依次向LruCache添加A,B,C,D试,正好LruCache容量已满,当添加第五个数据 E 时,LruCache会默认移除最先添加的 A,如果再添加 F,会移除 B。按照这个原理,LruCache会移除最近最少使用的数据。

四级缓存

Glide最为一个优秀的图片加载框架使用了四级缓存来加载图片。分别为ActiveResources 活动缓存,MemoryCache 内存缓冲,DiskCache 磁盘缓存,Http 网络缓存。如下图所示。

Glide的四级缓存实现比较复杂,分析源码时只关注主线流程。文章末尾用一张图来总结整个流程。篇幅较长,请耐心阅读

1.从Glideinto开始进行图片加载。


public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    
   .......省略部分代码......
 
    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        //请求配置参数
        requestOptions,
        //线程池
        Executors.mainThreadExecutor());
  }

2.构建一个请求任务,如果和上一个请求任务相同,则直接执行上一个请求任务。

private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> options,
      Executor callbackExecutor) {
      .....省略部分代码....
       //构建一个请求   
      Request request = buildRequest(target, targetListener, options, callbackExecutor);
      //获取上一个请求 
      Request previous = target.getRequest();
      //如果两个请求相同且已经完成请求
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        //重新开始执行上一个请求
        previous.begin();
      }
      return target;
    }
    //清除目标资源
    requestManager.clear(target);
    //资源绑定请求任务
    target.setRequest(request);
    //执行请求
    requestManager.track(target, request);

    return target;
  }

3.根据资源宽,高加载资源。


  @Override
  public void begin() {
    synchronized (requestLock) {
      ......省略部分代码......
       // 判断宽,高是否有效
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        onSizeReady(overrideWidth, overrideHeight);
      } else {
        //重新获取宽高  
        target.getSize(this);
      }
        ............
    }
  }

4.准备加载资源

public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
     ......省略部分代码......
      loadStatus =
          //执行数据请求
          engine.load(
              glideContext,
              model,
              requestOptions.getSignature(),
              this.width,
              this.height,
              .............,
              this,
              callbackExecutor);
    ...............
    }
  }

5.检查当前正在使用的资源集,如果存在则返回活动资源,并将任何新的不使用的资源移到内存缓存中。

检查内存缓存并提供缓存资源(如果存在)。

 public <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      ......................,
      ResourceCallback cb,
      Executor callbackExecutor) {
     ...........................
     //构建资源的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,
            ....................,
            cb,
            callbackExecutor,
            key,
            startTime);
      }
    }
     //将获取的资源回调回去
    cb.onResourceReady(
        memoryResource, DataSource.MEMORY_CACHE,  false);
    return null;
  }

6.首先从活动缓存loadFromActiveResources中获取资源。如果有直接返回,如果没有再从内存中查找资源loadFromCache,如果找到则返回,没有返回null。

 @Nullable
  private EngineResource<?> loadFromMemory(
      EngineKey key, boolean isMemoryCacheable, long startTime) {
     //设置不使用缓存
    if (!isMemoryCacheable) {
      return null;
    }
     //1 .首先从活动缓存activeResources中load资源
    EngineResource<?> active = loadFromActiveResources(key);
     //如果资源不为空直接返回
    if (active != null) {
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return active;
    }
    //2 .如果活动缓存中没有,则从内存中获取资源 
    EngineResource<?> cached = loadFromCache(key);
       //如果资源不为空直接返回
    if (cached != null) {
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return cached;
    }
    return null;
  }

7.如果从内存中获取到资源,将资源返回同时保存到活动缓存中,并移除内存中的资源。

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

8.如果活动缓存和内存缓存中都没有,则从磁盘缓存或网络中获取。返回第5步

private <R> LoadStatus waitForExistingOrStartNewJob(
      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,
      EngineKey key,
      long startTime) {
    //从缓存中获取执行任务
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
       //存在直接返回 
      current.addCallback(cb, callbackExecutor);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }
    //构建任务
    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);
  //构建解码任务
    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
           ..........
            engineJob);
   //添加任务队列
    jobs.put(key, engineJob);

    engineJob.addCallback(cb, callbackExecutor);
    //开始执行解码任务
    engineJob.start(decodeJob);
    ............
    return new LoadStatus(cb, engineJob);
  }

9.执行新的任务,engineJob.startdecodeJob放进线程池中执行。所以decodeJob中肯定有一个run方法。

 public void run() {
    .........................
    DataFetcher<?> localFetcher = currentFetcher;
    try {
        //取消
      if (isCancelled) {
        notifyFailed();
        return;
      }
        //执行任务
      runWrapped();
    } catch (CallbackException e) {
       //异常处理
        ....................
    }
  }

10.从初始状态INITIALIZE开始执行,获取当前资源执行器并执行

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

11.根据配置的资源状态获取执行器

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

12.根据判断当前任务执行情况,而获取下一个执行器执行。

 private void runGenerators() {
   ................
    while (!isCancelled
        && currentGenerator != null
          /判断是否是属于开始执行的任务
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();
     .................
 }

13.当执行到磁盘缓存执行器DataCacheGenerator,从磁盘缓存获取资源helper.getDiskCache().get(originalKey)。

public boolean startNext() {
    while (modelLoaders == null || !hasNextModelLoader()) {
      sourceIdIndex++;
      if (sourceIdIndex >= cacheKeys.size()) {
        return false;
      }
       //获取资源id
      Key sourceId = cacheKeys.get(sourceIdIndex);
      @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
      //创建资源key    
      Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
       //从磁盘缓存diskCacheProvider中获取缓存文件 
      cacheFile = helper.getDiskCache().get(originalKey);
       ............
    }

14.最后执行到源数据执行器SourceGenerator

 public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
        //将得到的数据保存到磁盘缓存中
      cacheData(data);
    }

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

15.当没有配置任何缓存时,最后一步就是网络请求了。loadData.fetcher.loadData就只能是从网络获取数据。

 private void startNextLoad(final LoadData<?> toStart) {
    loadData.fetcher.loadData(
        helper.getPriority(),
        new DataCallback<Object>() {
          @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);
            }
          }
        });
  }

16.最终执行到HttpUrlFetcher.loadData进行网络加载数据

@Override
  public void loadData(
      @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    try {
      //通过网络请求返回数据流  
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
      callback.onDataReady(result);
    } catch (IOException e) {
     ..............
    }
  }

17.获取流成功,将数据流返回,第15步

 public void onDataReady(@Nullable Object data) {
            if (isCurrentRequest(toStart)) {
              onDataReadyInternal(toStart, data);
            }
          }

void onDataReadyInternal(LoadData<?> loadData, Object data) {
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
    if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      //将得到的数据赋值给dataToCache
      dataToCache = data;
       
      cb.reschedule();
    } else {
      cb.onDataFetcherReady(
          loadData.sourceKey,
          data,
          loadData.fetcher,
          loadData.fetcher.getDataSource(),
          originalKey);
    }
  }

分析到这里,整个Glide图片缓存加载就结束,总结如下:

  1. 活动缓存:优先从活动缓存中查找资源,如果找到直接返回资源。当活动缓存中的资源释放时,将资源放入内存缓存。使用Map缓存资源
  2. 内存缓存:当活动缓存中找不到可用资源,从内存缓存中查找,同时将内存缓存中的资源放入活动缓存,并从内存缓存中移除资源。使用LruCache算法进行资源保存。
  3. 磁盘缓存:当内存缓存中也找不到可用资源,则从磁盘缓存中查找。同时将资源放入活动缓存。
  4. 网络缓存:当磁盘缓存中也找不到时,就从网络加载,并将请求返回的资源存入磁盘缓存中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值