Android 浅析Glide三级缓存

Android 简要分析Glide三级缓存

概括

Glide version is 4.8.0

Glide拥有三级缓存,分别为

  1. 当前正在使用得资源缓存(ActiveResources)
  2. 内存缓存(LruCache)
  3. 磁盘缓存(DiskLruCache)

LRU(Lest Resently Used)算法,在内存缓存和磁盘缓存中均有用得到,笔者写过一篇Kotlin版本的LruCache的实现,感兴趣的可以查看。Kotlin LruCache

缓存读取

缓存大致分为两大部分,内存缓存与磁盘缓存,而内存缓存又包含正在激活使用的弱引用缓存与LruCache。故为三级缓存。

内存

内存缓存默认开启,如需关闭则进行如下调用。

Glide.with(this)
     .load(url)
	  //关闭内存缓存
     .skipMemoryCache(true)
     .into(iv)

在图片加载过程中,会进去到Engine#load方法中,下面放上部分源代码:

  public <R> LoadStatus load(...){
  ...
    //获取缓存图片的key
    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);
	//从弱引用缓存中获取,若获取成功则返回并调用onResourceReady进行成功回调
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }
	//从内存缓存LruCache中获取,若成功获取则返回并调用onResourceReady进行成功回调
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }
    //若上方的缓存没用命中,则构建EngineJob,随后会进行磁盘缓存获取、网络请求
  ...
  }

上方总的流程是首先从弱引用缓存中取,再去从内存中去取。

首先分析一下弱引用缓存

  private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
      return null;
    }
    //从ActiveResources中获取资源
    EngineResource<?> active = activeResources.get(key);
    if (active != null) {
      //当前资源被引用了 +1
      active.acquire();
    }

    return active;
  }
  final class ActiveResources {
    //HashMap 中 储存了弱引用资源
  	final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
  }

内存缓存LruCache

private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
  if (!isMemoryCacheable) {
    return null;
  }
  //内部调用remove方法,返回当前资源并且将其从内存LruCache中移除
  EngineResource<?> cached = getEngineResourceFromCache(key);
  if (cached != null) {
    //资源被引用+1
    cached.acquire();
    //将当前资源加入到 弱引用集合
    activeResources.activate(key, cached);
  }
  return cached;
}

上方的注释很明确了,但是我们发现,内存的二级缓存中存在着交互,比如说,如果从内存LruCache中找到资源后,内存中就将该资源移除了,转而加入到弱引用集合中了。

那么上面还有一个资源引用数+1是干什么的呢?

它主要统计当前资源被多少个地方引用/使用(一张图片被多个地方展示),其中被引用一次就+1,这时候资源肯定都在弱引用集合,如果不引用资源了就-1,直到引用数为0,就将资源从弱引用集合存入到内存LruCache。

总的来说,弱引用集合存的是当前正在使用的资源(若不使用,随时被系统回收),重复利用;内存LruCache,存的则是,之前使用过但当前不再使用过的资源。二者之间存在交互。

而整体内存缓存主要的作为即为防止同一张图片(包括尺寸大小都一样)的资源,被重复加入内存,同时提高相应速度。

磁盘

磁盘缓存有存在以下五种策略:默认为AUTOMATIC

  • ALL 远程图片资源使用 DATA 和 RESOURCE 缓存,本地图片只使用 RESOURCE 缓存;
  • NONE 不缓存任何图片资源;
  • DATA 将检索到的原始图片资源(解码之前的)写入磁盘缓存;
  • RESOURCE 将检索到的原始图片资源解码之后(压缩或转换)再写入磁盘缓存;
  • AUTOMATIC 尝试根据数据源智能选择策略,数据源可以是:DataFetcher、EncodeStrategy、ResourceEncoder;

使用diskCacheStrategy可以调整缓存策略,比如:

Glide.with(this)
     .load(url)
     .diskCacheStrategy(DiskCacheStrategy.ALL)
     .into(iv);

若上方内存二级缓存没用命中,则会执行到接下来的流程DecodeJob#onDataFetcherReady

  @Override
  public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
      DataSource dataSource, Key attemptedKey) {
    ...
      try {
        //会从磁盘获取数据
        decodeFromRetrievedData();
      } finally {
        GlideTrace.endSection();
      }
    }
  }

总结

三级缓存读取顺序为:弱引用缓存 -> LruCache -> DiskLruCache。

创作不易,如有帮助一键三连咯🙆‍♀️。欢迎技术探讨噢!

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pumpkin的玄学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值