Glide——缓存分析整理

LruCache

概述

LruCache是Android 3.1所提供的一个缓存类,所以在Android中可以直接使用LruCache实现内存缓存。

主要算法原理是把最近使用的对象用强引用(即我们平常使用的对象引用方式)存储在 LinkedHashMap 中。当缓存满时,把最近最少使用的对象从内存中移除,并提供了get和put方法来完成缓存的获取和添加操作。

简单使用

int maxMemory = (int) (Runtime.getRuntime().totalMemory()/1024);
int cacheSize = maxMemory/8;
mMemoryCache = new LruCache<String,Bitmap>(cacheSize){
   
        @Override
        protected int sizeOf(String key, Bitmap value) {
   
            return value.getRowBytes()*value.getHeight()/1024;
        }
    };
  • 设置LruCache缓存大小
  • 重写sizeOf方法计算每张图片大小

原理

维护一个缓存对象列表,其中对象列表的排列方式是按照访问顺序实现的,即一直没访问的对象,将放在队尾,即将被淘汰。而最近访问的对象将放在队头,最后被淘汰。

在这里插入图片描述
这个队列的维护基于LinkedHashMap。

LruCache中维护了一个集合LinkedHashMap,该LinkedHashMap是以访问顺序排序的。当调用put()方法时,就会在结合中添加元素,并调用trimToSize()判断缓存是否已满,如果满了就用LinkedHashMap的迭代器删除队尾元素,即近期最少访问的元素。当调用get()方法访问缓存对象时,就会调用LinkedHashMap的get()方法获得对应集合元素,同时会更新该元素到队头。

https://www.jianshu.com/p/b49a111147ee

DiskLruCache

概述

DiskLruCache 的分析分为两部分:分别是日志,读、写缓存。

DiskLruCache 的日志就是一个操作记录。例如,删除一条缓存条目,就会在日志文件中记录一条 REMOVE 记录;新建一条缓存,缓存文件刚建立时会增加一条 DIRTY 记录,缓存写入成功后再增加一条 CLEAN 记录;缓存被读取,会增加 READ 记录。日志文件的格式如下:
在这里插入图片描述

记录日志是为了在 DiskLruCache 初始化时建立起缓存的 LRU 结构。DiskLruCache 内部使用了 LinkHashMap 来存储所有的缓存项,在初始化的时候,DiskLruCache 会读日志文件上的记录,根据该日志文件的记录将所有历史操作“重做”一遍:在执行历史操作时,会根据日志记录对缓存项进行添加和删除操作。为什么这样能保证缓存项是按 LRU 的顺序排序的呢?因为构造 LinkedHashMap 的时候选择使用 Access Order(访问顺序)来保持元素的顺序,因此只需遍历日志根据日志记录向 LinkedHashMap 中放入缓存项(Entry)自然而然地就保持了 LRU 的顺序。

http://liwenkun.me/2017/08/29/glide-disk-cache-strategy/

Glide缓存概述

资源分类

Glide的缓存图片资源分为两类

  • 原始图片(Source)——原始图片大小
  • 转换后的图片(Result)——经过大小处理过的图片

使用Glide加载图片时,Glide默认会根据View对图片进行压缩转换。

缓存设计

  • Glide缓存设计为二级缓存:内存缓存和硬盘缓存
  • 缓存读取顺序:内存缓存 --> 磁盘缓存 --> 网络
  • 内存缓存:防止应用重复将图片数据读取内存当中——只缓存转换过后的图片
  • 硬盘缓存:防止应用重复从网络或其他地方重复下载和读取数据——可缓存原始图片、转换过后的图片

Glide内存缓存实现基于LruCache 算法 + 弱引用机制

  • LruCache算法原理:将最近使用的对象,用强引用的方式 存储在LinkedHashMap中 ;当缓存满时 ,将最近最少使用的对象从内存中移除
  • 弱引用:弱引用的对象具备更短生命周期,因为 当JVM进行垃圾回收时,一旦发现弱引用对象,都会进行回收(无论内存充足否)

磁盘缓存使用Glide 自定义的DiskLruCache算法

  • 该算法基于 Lru 算法中的DiskLruCache算法,具体应用在磁盘缓存的需求场景中
  • 该算法被封装到Glide自定义的工具类中(该工具类基于Android 提供的DiskLruCache工具类)

Glide 缓存源码分析

1、生成key

Glide实现内存、磁盘缓存是根据图片缓存key进行唯一标识

生成缓存 Key 的代码发生在Engine类的 load()中

    public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
            DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
            Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
   
        Util.assertMainThread();
        long startTime = LogTime.getLogTime();

        final String id = fetcher.getId();
        // 获得了一个id字符串,即需加载图片的唯一标识
        // 如,若图片的来源是网络,那么该id = 这张图片的url地址

        EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),transcoder, loadProvider.getSourceEncoder());
        // Glide的缓存Key生成规则复杂:根据10多个参数生成
        // 将该id 和 signature、width、height等10个参数一起传入到缓存Key的工厂方法里,最终创建出一个EngineKey对象
        // 创建原理:通过重写equals() 和 hashCode(),保证只有传入EngineKey的所有参数都相同情况下才认为是同一个EngineKey对象
        // 该EngineKey 即Glide中图片的缓存Key

        ... 

概括一下

  • 获得了一个id字符串,若图片的来源是网络,那么该id = 这张图片的url地址
  • Glide的缓存Key生成规则:根据10多个参数生成,将该id 和 signature、width、height等10个参数一起传入到缓存Key的工厂方法里,最终创建出一个EngineKey对象

2、创建缓存对象LruResourceCache

LruResourceCache对象是在创建 Glide 对象时创建的

public class GlideBuilder {
   
    ...
    Glide createGlide() {
   
        MemorySizeCalculator calculator = new MemorySizeCalculator(context);
        if (bitmapPool == null) {
   
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
   
                int size = calculator.getBitmapPoolSize();
                bitmapPool = new LruBitmapPool(size);
            } else {
   
                bitmapPool = new BitmapPoolAdapter();
            }
        }

        if (memoryCache == null) {
   
            memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
            // 创建一个LruResourceCache对象 并 赋值到memoryCache对象
            // 该LruResourceCache对象 = Glide实现内存缓存的LruCache对象

        }
        
        return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
    }
} 

这里没什么多说的。

3、获取内存缓存中的图片

读取内存缓存代码实在Engine类的load()方法中

    public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
            DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
            Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
   
        Util.assertMainThread();

        final String id = fetcher.getId();
        EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值