• Glide缓存机制


    1 Glide图片加载流程

    图片加载描述

    1. 封装参数:从指定来源到输出结果,中间可能经历很多流程,所以第一件事就是封装参数,这些参数会贯穿整个图片加载流程;
    2. 解析路径:图片的来源有很多种,格式也不尽相同,需要规范化;
    3. 读取缓存:为了减少计算,通常会做缓存,优先从缓存中读取;
    4. 查找文件/下载文件:如果是本地文件,直接解码即可,如果是网络图片,需要下载;
    5. 解码:
    6. 变换:解码出Bitmap后,可能还需要做一些变换处理(圆角,滤镜等);
    7. 缓存:得到最终的Bitmap止呕,可以缓存起来,以便下次使用;
    8. 显示:显示结果,可能需要做一些动画等;

    2 Glide缓存机制简介

    2.1 缓存的图片资源

    • 原始图片(Source) :即图片源的图片初始大小和分辨率;
    • 转换后的图片(Result) :经过尺寸缩放和大小压缩等处理后的图片;

    当使用Glide加载图片时,Glide会默认根据View视图对图片进行压缩和转换,而不显示原始图。(这也是Glide加载速度高于Picasso的原因)

    2.2 缓存机制设计

    Glide的缓存功能设计成二级缓存:内存缓存和硬盘缓存。(从网络加载不属于缓存)

    • 内存缓存:防止重复将图片读入到内存,造成内存资源浪费,只缓存转换后的图片,而不是原始图片;
    • 磁盘缓存:防止重复从网络或其他地方下载和读取数据,可缓存原始图片和转换过后的图片,用户自行设置;

    Glide中,缓存的读取顺序为:内存缓存 –> 磁盘缓存 –> 网络 ,内存缓存和磁盘缓存相互不影响,独立配置,内存缓存是默认开启的。

    Glide的缓存机制使得Glide具备非常好的图片缓存效果,从而使得具备较高的图片加载效率。

    以下是Glide的相关代码:

    // 默认开启内存缓存,用户不需要作任何设置
    Glide.with(this).load(url).into(imageView);
    
    // 可通过API禁用内存缓存功能
    Glide.with(this).load(url).skipMemoryCache(true) // 禁用内存缓存
         .into(imageView);
    
    Glide.with(this).load(url)
         .diskCacheStrategy(DiskCacheStrategy.NONE) // 不缓存任何图片,即禁用磁盘缓存
         .into(imageView);
    
    // DiskCacheStrategy.NONE:不缓存任何图片,即禁用磁盘缓存
    // DiskCacheStrategy.ALL :缓存原始图片 & 转换后的图片
    // DiskCacheStrategy.SOURCE:只缓存原始图片(原来的全分辨率的图像,即不缓存转换后的图片)
    // DiskCacheStrategy.RESULT:(默认)只缓存转换后的图片(即最终的图像:降低分辨率后 / 或者转换后 ,不缓存原始图片
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.3 缓存类型

    • 活动缓存(ActiveResource):存储正在使用的图片;
    • Lru内存缓存(LruResourceCache):图片解析完成后并最近被加载过会放到内存中;
    • 磁盘缓存-资源类型(DiskCache - Resource):被解码后的图片写入磁盘文件中;
    • 磁盘缓存-原始数据(DiskCache - Data):网络请求成功或在本地获取成功后,将原始数据在磁盘中缓存;

    Lru(Least Recently Used):最近最少使用,它的核心思想是,当缓存满的时候,会优先淘汰最近最少使用的缓存对象。

    在这里插入图片描述

    2.3.1 内存缓存/运行时缓存

    内存缓存/运行时缓存分为两部分:活动缓存(ActiveResource)和Lru内存缓存(LruResourceCache)。

    LinkedHashMap继承自HashMap,在此基础上增加了双向链表的结构,每次访问数据的时候,会更新被访问的数据的链表指针。比如说从链表中删除并不是真正的删除数据,只是移动了链表的指针。

    双向链表

    Lru内存缓存:使用LinkedHashMap来缓存资源(强引用),并设定一个缓存的大小。如果有资源被访问到,首先会在链表中删除该节点,然后再添加到链表头,这样就可以保证链表头部的节点是最近访问过的。而当缓存的数量达最大值的时候,就会将链表尾部(最近最少使用)的数据移除。

    但是这样做有一个风险,就是容易将正在使用的资源回收掉。

    Glide这样设计:从内存缓存(LruResourceCache)中拿到资源时候就主动添加到活动缓存(ActiveResource)中,并清理Lru内存缓存(LruResourceCache)中的资源,这样做的好处就是是保护正在使用资源不被Lru算法回收掉。

    ActiveResources是一个弱引用的HashMap,用来缓存正在使用的图片,保存这个图片不会被Lru算法回收掉。图片用完之后会重新添加到Lru内存缓存中。

    ActiveResourcesLruResourceCache是内存缓存,属于运行时缓存且互斥(同一张图片不会同时缓存在ActiveResourcesLruResourceCache中),应用被杀死后内存缓存将不存在。

    2.3.2 磁盘缓存

    磁盘缓存策略:

    • DiskCacheStrategy.NONE:表示不缓存任何内容;
    • DiskCacheStrategy.RESOURCE:在资源解码后将数据写入磁盘缓存,即经过缩放等转换后的图片资源;
    • DiskCacheStrategy.DATA:在资源解码前将原始数据写入磁盘缓存;
    • DiskCacheStrategy.ALL :使用DATARESOURCE缓存数据;
    • DiskCacheStrategy.AUTOMATIC:它会尝试对本地和远程图片使用最佳的策略。当加载远程数据时,AUTOMATIC 策略仅会存储未被加载过程修改过的原始数据,因为下载远程数据相比调整磁盘上已经存在的数据要昂贵得多。对于本地数据,AUTOMATIC 策略则会仅存储变换过的缩略图,因为即使需要再次生成另一个尺寸或类型的图片,取回原始数据也很容易。默认使用这种缓存策略;

    在使用Glide去加载一张图片的时候,Glide默认不会将原始图片展示出来,而是会对图片进行压缩和转换。我们既可以缓存转换过的图片,也可以缓存转换之前的原始图片。

    采用LRU算法的缓存有两种:LruCacheDisLruCache,分别用于实现内粗缓存和硬盘缓存。

    3 大图加载

    对于单个图片巨大,并且还不允许压缩。比如显示:世界地图、清明上河图、微博长图等。

    首先不压缩,按照原图尺寸加载,那么屏幕肯定是不够大的,并且考虑到内存的情况,不可能一次性整图加载到内存中,所以这种情况的优化思路一般是局部加载,通过BitmapRegionDecoder来实现。BitmapRegionDecoder可以从图像中解码一个矩形区域,只显示图像的一部分。这种情况下通常Glide只负责将图片下载下来,图片的加载由自定义的ImageView来实现。

    图片分块以后,每一块独立进行加载,并且加载bitmap是一个耗时操作,将加载bitmap异步实现。分块好后还有一个触发加载和回收的逻辑,原则是在它显示的范围内就触发加载,离开范围后就回收。

    region [ˈriːdʒən] 地区,区域,界 decoder [diːˈkoʊdər] 解码器,译码器;译码员

    demo

    参考

    Glide 缓存总结(一)
    Android源码分析:手把手带你分析 Glide的缓存功能
    Glide源码之缓存机制Glide源码之缓存机制
    Android Glide缓存机制及源码
    浅谈Glide的原理
    聊一聊关于Glide在面试中的那些事
    【Android 内存优化】Bitmap 长图加载 ( BitmapRegionDecoder 简介 | BitmapRegionDecoder 使用流程 | 区域解码加载示例 )
    学习笔记-android大图加载详解
    如何解决android大量图片的帧动画卡顿和OOM问题?

  • 相关阅读:
    【centos7】centos7卸载gitlab
    破解软件的原理是什么(软件被破解公开)
    测试日记day4
    逻辑回归原理
    [附源码]java毕业设计医药管理系统
    l8-d15 IO多路复用select函数
    编码揭秘:解构字符%20背后的秘密与百分号编码艺术
    阿里为了双十一,整理亿级JVM性能优化文档,竟被GitHub“抢开”
    【vue3】踩坑日记,vite与node版本对应(mac环境)
    ArduPilot添加新的惯导方案
  • 原文地址:https://blog.csdn.net/xingyu19911016/article/details/125442418