当前位置: 首页 > news >正文

Glide 缓存机制研究及同命名图片的替换回显

背景:

相册-图片后处理场景,需要先展示一张原图,同时后台对图片进行算法优化,完成优化之后无缝替换原图展示,同时保证后续都展示算法优化后的图片

图片加载采用 Glide 库实现

画重点:

  1. 相册场景:意味着存在图片缓存的复用

  2. 无缝替换:切换过程要很丝滑,不能有闪烁等现象

  3. 后续展示优化后的图片:说明后续缓存要复用算法优化后的,不能用原图

  4. 因为是对图片进行优化,所以原图和算法优化后的图片文件名一样

最开始的想法:

步骤:

  1. 先加载原图展示

  2. 等图片算法优化,重新调用 glide 加载一遍

结果:

  1. 重新加载之后,还是原图效果

Glide 缓存机制

基于上述原因,专门研究了下 Glide 的缓存机制,重点是缓存的读取这一块

四级缓存机制

Glide 采用四级缓存机制,主要分成两个模块,内存缓存,硬盘缓存

  • 内存缓存:防止应用重复将图片数据读到内存中
  • 硬盘缓存:防止应用重复从网络或者其他地方重复下载和读取数据
  • 缓存Key:既然有缓存,那肯定需要对应的缓存Key,通过按照一定规则生成缓存key之后,根据key从缓存集中取出对应缓存复用

这里先简单讲下四级缓存机制,然后再跟着源码过一遍

内存缓存-lru缓存:

Glide 在内存中维持的一个缓存 map,通过 lru 算法实现内存管理

private final LinkedHashMap<T, Y> cache = new LinkedHashMap<T, Y>(100, 0.75f, true);
​
T:缓存Key
Y:缓存资源

内存缓存-弱引用缓存:

Glide 在内存中维持的一个弱引用缓存 map,由于是弱引用,这就意味着内存不足的时候先销毁这个

private final Map<Key, WeakReference<EngineResource<?>>> activeResources;

硬盘缓存-转换过缓存:

Glide 在硬盘上的缓存,该缓存是经过各种变换后的缓存,不是原始图片

硬盘缓存-原始图片缓存:

Glide 在硬盘上的缓存,该缓存是原始图片缓存

Glide 缓存加载流程:

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();// 1. 生成 缓存key,可以看出 key 的生成用到很多参数,比如 id(图片路径)、signature、width、height,还有 transformationEngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),transcoder, loadProvider.getSourceEncoder());
​// 2. 先从内存缓存-lru缓存中拿缓存,如果拿到缓存调用 onResourceReadyEngineResource<?> cached = loadFromCache(key, isMemoryCacheable);if (cached != null) {cb.onResourceReady(cached);if (Log.isLoggable(TAG, Log.VERBOSE)) {logWithTimeAndKey("Loaded resource from cache", startTime, key);}return null;}// 3. 内存缓存-lru中没有缓存,则从弱引用缓存中拿,如果拿到调用 onResourceReadyEngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);if (active != null) {cb.onResourceReady(active);if (Log.isLoggable(TAG, Log.VERBOSE)) {logWithTimeAndKey("Loaded resource from active resources", startTime, key);}return null;}// 4. 内存缓存-弱引用中也没有缓存,从硬盘缓存中拿或加载文件地址,不管是拿硬盘缓存还是加载文件,涉及到IO操作,需要子线程处理EngineJob current = jobs.get(key);if (current != null) {current.addCallback(cb);if (Log.isLoggable(TAG, Log.VERBOSE)) {logWithTimeAndKey("Added to existing load", startTime, key);}return new LoadStatus(cb, current);}
​EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,transcoder, diskCacheProvider, diskCacheStrategy, priority);EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);jobs.put(key, engineJob);engineJob.addCallback(cb);engineJob.start(runnable);
​if (Log.isLoggable(TAG, Log.VERBOSE)) {logWithTimeAndKey("Started new load", startTime, key);}return new LoadStatus(cb, engineJob);
}

内存缓存-lru缓存中拿缓存:

private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {if (!isMemoryCacheable) {return null;}// 如果从 lru 中能拿到缓存,将该缓存从 lru 缓存中移除,并存入 弱引用缓存EngineResource<?> cached = getEngineResourceFromCache(key);if (cached != null) {cached.acquire();activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));}return cached;
}

从硬盘缓存中拿或加载文件地址:

private Resource<?> decode() throws Exception {// 这里有个策略判断,只有支持硬盘缓存策略,才能从硬盘中拿缓存if (isDecodingFromCache()) {// 从硬盘缓存中拿return decodeFromCache();} else {// 加载文件return decodeFromSource();}
}​
// 从硬盘缓存中拿
private Resource<?> decodeFromCache() throws Exception {Resource<?> result = null;try {// 5. 从硬盘缓存-转换过缓存中拿result = decodeJob.decodeResultFromCache();} catch (Exception e) {if (Log.isLoggable(TAG, Log.DEBUG)) {Log.d(TAG, "Exception decoding result from cache: " + e);}}
​if (result == null) {// 6. 硬盘缓存-转换过缓存中拿不到,从原始图片缓存中拿result = decodeJob.decodeSourceFromCache();}return result;
}
​
// 从硬盘缓存-转换过缓存中拿
public Resource<Z> decodeResultFromCache() throws Exception {if (!diskCacheStrategy.cacheResult()) {return null;}
​long startTime = LogTime.getLogTime();Resource<T> transformed = loadFromCache(resultKey);if (Log.isLoggable(TAG, Log.VERBOSE)) {logWithTimeAndKey("Decoded transformed from cache", startTime);}startTime = LogTime.getLogTime();Resource<Z> result = transcode(transformed);if (Log.isLoggable(TAG, Log.VERBOSE)) {logWithTimeAndKey("Transcoded transformed from cache", startTime);}return result;
}
​
// 从硬盘缓存-原始图片缓存中拿
public Resource<Z> decodeSourceFromCache() throws Exception {if (!diskCacheStrategy.cacheSource()) {return null;}
​long startTime = LogTime.getLogTime();// 这里值得注意的是,这里用的key和其他三个缓存中用到的不一样,这里用的是 resultKey.getOriginalKey() 就是原始图片地址,不过也能理解,加载原始图片缓存,也不需要额外的key信息,只需要文件地址就行了Resource<T> decoded = loadFromCache(resultKey.getOriginalKey());if (Log.isLoggable(TAG, Log.VERBOSE)) {logWithTimeAndKey("Decoded source from cache", startTime);}return transformEncodeAndTranscode(decoded);
}

理完Glide的加载机制之后,就很好理解为什么重新加载之后还是原图,所以进行了优化

优化方案二

加载原图时:

glideOptions = new RequestOptions().signature(new ObjectKey(signatureKey));

加载优化后图片时:

glideOptions = new RequestOptions();

加载原图时多调用了 signature 方法,这样加载优化后图片时,由于和加载原图时的缓存key不一样,会重新进行加载

优化方案二解决了优化图片不加载问题,但是由于重新加载图片,会导致切换过程出现很明显的闪烁,这里可以通过 placeholder 方法优化

优化方案三

// 1. 获取当前 imageView 的 drawable
Drawable drawable = imageView.getDrawable();
Bitmap placeholderBitmap = null;
// 2. drawable 转成 bitmap
if(drawable instanceof BitmapDrawable){placeholderBitmap = ((BitmapDrawable) drawable).getBitmap();
}
// 3. 由于 imageView 的 drawable 可能会被回收,所以需要将 bitmap 重新 clone 一份
Bitmap copiedBitmap = null;
if(placeholderBitmap != null){copiedBitmap = placeholderBitmap.copy(placeholderBitmap.getConfig(), true);
}
// 4. 将 bitmap 作为 占位符传入
if(copiedBitmap != null && !copiedBitmap.isRecycled()){glideOptions = new RequestOptions().frame(0).placeholder(new BitmapDrawable(context.getResources(), copiedBitmap)).override(size.getWidth(), size.getHeight());
}else {glideOptions = new RequestOptions().frame(0).override(size.getWidth(), size.getHeight());
}

至此,效果实现!

相关文章:

Glide 缓存机制研究及同命名图片的替换回显

背景&#xff1a; 相册-图片后处理场景&#xff0c;需要先展示一张原图&#xff0c;同时后台对图片进行算法优化&#xff0c;完成优化之后无缝替换原图展示&#xff0c;同时保证后续都展示算法优化后的图片 图片加载采用 Glide 库实现 画重点&#xff1a; 相册场景&#xff…...

一键简易桌签(带背景)-Word插件-大珩助手

问题整理&#xff1a; 如何Word中设计简易桌签&#xff1f;如何设置带背景图的桌签&#xff1f; Word大珩助手是一款功能丰富的Office Word插件&#xff0c;旨在提高用户在处理文档时的效率。它具有多种实用的功能&#xff0c;能够帮助用户轻松修改、优化和管理Word文件&…...

如何解决centos停止维护后更换Debian11平替?

再有9天时间centos7.x就将停止维护,最近很多人已经再更换系统了!有推荐alibabacloud,opencloud,debian,ubuntu,centos-stream,tencentos,anolis,rockey,almal,oracle,arch,Fedora,opensuse 很多人不知道选什么,这里就主要介绍一下 如果你是使用宝塔面板 并且想要无缝衔…...

服务器雪崩的应对策略之----熔断机制

熔断机制&#xff08;Circuit Breaker&#xff09;是一种保护系统稳定性的重要手段。它的主要目的是防止系统在依赖的服务出现问题时&#xff0c;继续发送请求&#xff0c;从而保护系统免受进一步的影响。熔断机制通过监控请求的成功和失败率&#xff0c;在检测到故障率超过预设…...

RestClient操作索引库和文档

导入依赖&#xff1a; <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.12.1</version></dependency>导入依赖成功之后就可以开始我们的测…...

【设计模式深度剖析】【11】【行为型】【解释器模式】| 以算术表达式求值为例加深理解

&#x1f448;️上一篇:状态模式 设计模式-专栏&#x1f448;️ 文章目录 解释器模式定义英文原话直译 解释器模式中的角色1. 抽象表达式&#xff08;AbstractExpression&#xff09;2. 终端表达式&#xff08;TerminalExpression&#xff09;3. 非终端表达式&#xff08;Non…...

MySQL8,Navicat能登陆成功,密码却忘记了

执行成功的图&#xff1a; 以下为步骤&#xff1a;本文一共8个简单步骤。 环境&#xff1a;mysql8、window10、navicat11 1、打开本地电脑window10的命令窗&#xff08;俗称黑窗口&#xff09;&#xff0c;windowR 2、输入regegit&#xff0c;回车&#xff0c;打开注册表 3、…...

游戏中的寻路算法研究

1)Unity NavMesh研究 思考&#xff1a;毫无疑问&#xff0c;unity中自带的navmesh寻路是比较健全的&#xff0c;无奈在服务器中无法使用&#xff0c;这样子我们没办法做怪的导航&#xff0c;但是可以先体验下都有哪些api&#xff0c;并且可以可视化的看效果。 1)打开导航网格…...

【AWS SMB】关于AWS 中小型企业 (SMB) 能力介绍及注意事项

文章目录 前言一、什么是 SMB&#xff1f;&#x1f4e2;二、如何识别中小企业的需求三、中小企业营销活动的类型四、AWS 合作伙伴可获得的其他 AWS 机会4.1 AWS IQ4.2 APN 客户参与 (ACE) 计划 前言 AWS 中小型企业 &#xff08;SMB&#xff09; 能力合作伙伴专注于帮助中小型…...

中年之恋:重返青春的旅程

第一章&#xff1a;重逢 在一个普通的周末&#xff0c;李明参加了一次由老同学组织的聚会&#xff0c;尽管他对此并不抱有太大的兴趣&#xff0c;但出于礼貌还是选择了出席。聚会在一家风格复古的咖啡馆里举行&#xff0c;暖黄色的灯光与木质的装饰让人不自觉地放缓了脚步。在…...

人工智能中的监督学习和无监督学习

欢迎来到 Papicatch的博客 目录 &#x1f349;引言 &#x1f349;监督学习 &#x1f348;基本思想 &#x1f348;具体过程 &#x1f34d;数据收集 &#x1f34d;数据预处理 &#x1f34d;模型选择 &#x1f34d;模型训练 &#x1f34d;模型评估 &#x1f34d;模型部署…...

深度学习500问——Chapter12:网络搭建及训练(1)

文章目录 12.1 TensorFlow 12.1.1 TensorFlow 是什么 12.1.2 TensorFlow的设计理念是什么 12.1.3 TensorFlow特点有哪些 12.1.4 TensorFlow的系统架构是怎样的 12.1.5 TensorFlow编程模型是怎样的 12.1.6 如何基于TensorFlow搭建VGG16 12.1 TensorFlow 12.1.1 TensorFlow 是什…...

HuggingFace CLI 命令全面指南

文章目录 安装与认证1.1 安装 HuggingFace Hub 库使用 pip 安装使用 conda 安装验证安装 1.2 认证与登录生成访问令牌使用访问令牌登录环境变量认证验证认证 下载文件2.1 下载单个文件安装 huggingface_hub 库认证与登录下载单个文件 2.2 下载特定版本的文件下载特定版本的文件…...

FreeRTOS源码分析

目录 1、FreeRTOS目录结构 2、核心文件 3、移植时涉及的文件 4、头文件相关 4.1 头文件目录 4.2 头文件 5、内存管理 6、入口函数 7、数据类型和编程规范 7.1 数据类型 7.2 变量名 7.3 函数名 7.4 宏的名 1、FreeRTOS目录结构 使用 STM32CubeMX 创建的 FreeRTOS 工…...

python实战:将视频内容上传到社交媒体平台

在Python中&#xff0c;上传视频到不同的平台可能需要使用不同的API和库。以下是一些常见的平台以及如何使用Python进行上传的示例&#xff1a; YouTube: 使用Google提供的YouTube Data API。 首先&#xff0c;你需要从Google Cloud控制台获取API密钥&#xff0c;并安装google-…...

【深度学习】sdwebui A1111 加速方案对比,xformers vs Flash Attention 2

文章目录 资料支撑资料结论sdwebui A1111 速度对比测试sdxlxformers 用contorlnet sdxlsdpa&#xff08;--opt-sdp-no-mem-attention&#xff09; 用contorlnet sdxlsdpa(--opt-sdp-attention) 用contorlnet sdxl不用xformers或者sdpa ,用contorlnet sdxl不用xformers或者sdpa …...

5分钟了解单元测试

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、什么是单元测试&#xff1f; 单元测试是指&#xff0c;对软件中的最小可测试单元在与程序其…...

VSCode之C/C++插件之宏定义导致颜色变暗

这是因为该宏没有定义或者定义在makefile文件中导致无法被插件识别到&#xff0c;导致误判了 索性将该机制去了&#xff0c;显示也会好看些&#xff0c;如下将C_Cpp下的Dim Inactive Regions勾去了 显示效果会好很多。...

自然语言处理概述

目录 1.概述 2.背景 3.作用 4.优缺点 4.1.优点 4.2.缺点 5.应用场景 5.1.十个应用场景 5.2.文本分类 5.2.1.一般流程 5.2.2.示例 6.使用示例 7.总结 1.概述 自然语言处理&#xff08;NLP&#xff09;是计算机科学、人工智能和语言学的交叉领域&#xff0c;旨在实…...

用Rust和Pingora轻松构建超越Nginx的高效负载均衡器

目录 什么是Pingora&#xff1f;实现过程 初始化项目编写负载均衡器代码代码解析部署 总结 1. 什么是Pingora&#xff1f; Pingora 是一个高性能的 Rust 库&#xff0c;用于构建可负载均衡器的代理服务器&#xff0c;它的诞生是为了弥补 Nginx 存在的缺陷。 Pingora 提供了…...

华为云与AWS负载均衡服务深度对比:性能、成本与可用性

随着云计算的迅速发展&#xff0c;企业对于云服务提供商的选择变得越来越关键。在选择云服务提供商时&#xff0c;负载均衡服务是企业关注的重点之一。我们九河云将深入比较两大知名云服务提供商华为云和AWS的负载均衡服务&#xff0c;从性能、成本和可用性等方面进行对比。 AW…...

Vue65-组件之间的传值

1、收数据 2、传数据 3、批量的数据替换 若是info里面有四个数据&#xff0c;传过来的dataObj里面有三个数据&#xff0c;则info里面也只有三个数据了 解决方式&#xff1a; 该写法还有一个优势&#xff1a;传参的时候&#xff0c;顺序可以随意&#xff01;...

Java零基础之多线程篇:线程生命周期

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…...

技术差异,应用场景;虚拟机可以当作云服务器吗

虚拟机和云服务器是现在市面上常见的两种计算资源提供方式&#xff0c;很多人把这两者看成可以相互转换或者替代的物品&#xff0c;实则不然&#xff0c;这两种资源提供方式有许多相似之处&#xff0c;但是也有不少区别&#xff0c;一篇文章教你识别两者的技术差异&#xff0c;…...

Qt Quick 教程(一)

文章目录 1.Qt Quick2.QML3.Day01 案例main.qml退出按钮&#xff0c;基于上面代码添加 4.使用Qt Design StudioQt Design Studio简介Qt Design Studio工具使用版本信息 1.Qt Quick Qt Quick 是一种现代的用户界面技术&#xff0c;将声明性用户界面设计和命令性编程逻辑分开。 …...

react钩子函数用法(useCallback、useMemo)

useMemo import { useMemo } from react; function MyComponent({ a, b }) { const memoizedValue useMemo(() > { // 进行一些昂贵的计算 return a b; }, [a, b]); // 当 a 或 b 发生变化时&#xff0c;memoizedValue 将被重新计算 return <div>{memoizedVa…...

linux配置Vnc Server给Windows连接

1. linux 安装必要vnc server和桌面组件 sudo apt -y install tightvncserversudo apt install xfce4 xfce4-goodies2. linux 配置vncserver密码 #bash vncserver参考: https://cn.linux-console.net/?p21846#google_vignette 3. 将启动桌面命令写入.vnc/xstartup # .vnc/x…...

Android中的KeyEvent详解

介绍 在Android中&#xff0c;KeyEvent 是用来表示按键事件的类&#xff0c;可根据对应的事件来处理按键输入&#xff0c;具体包含了关于按键事件的信息&#xff0c;例如按键的代码、动作&#xff08;按下或释放&#xff09;以及事件的时间戳&#xff0c;KeyEvent 对象通常在用…...

移植案例与原理 - HDF驱动框架-驱动配置(2)

1.2.7 节点复制 节点复制可以实现在节点定义时从另一个节点先复制内容&#xff0c;用于定义内容相似的节点。语法如下&#xff0c;表示在定义"node"节点时将另一个节点"source_node"的属性复制过来。 node : source_node示例如下&#xff0c;编译后bar节点…...

年终奖发放没几天,提离职领导指责我不厚道,我该怎么办?

“年终奖都发了&#xff0c;你还跳槽&#xff1f;太不厚道了吧&#xff01;” “拿完年终奖就走人&#xff0c;这不是典型的‘骑驴找马’吗&#xff1f;” 每到岁末年初&#xff0c;关于“拿到年终奖后是否应该立即辞职”的话题总会引发热议。支持者认为&#xff0c;这是个人…...

自己做的网站不显示图片/网页设计一般用什么软件

这几天在搞自己的tts语音合成服务端&#xff0c; 去年一直用的百度免费的text2audio接口&#xff0c;前几天突出不能用了&#xff0c; 客户哇哇大叫&#xff0c; 没办法&#xff0c;小公司&#xff0c;本来就是用来播报一些简单的文字&#xff0c;但没有就又不行 于是干脆w…...

基于java的音乐网站开发/做seo必须有网站吗

Entity Framwork 学习笔记 (二) 生成 数据 ADO.NET 数据实体模型 Entity Framwork 学习笔记 (二) 生成 数据 ADO.NET 数据实体模型 添加 ADO.NET 实体数据模型项模板 在“解决方案资源管理器”中选择 CourseManager 项目&#xff0c;右键单击&#xff0c;指向“添加”&#xff…...

网站艺术设计/微信推广引流加精准客户

jQuery has been removed, 新的项目不要用jQuery了 这些问题都已经有了解决方案 * $()选择器, * $.ajax, * $dom.on("click", function() {}), * HTML5 API兼容 * 自定义html标签 对应如下&#xff1a; * querySelectorAll - http://youmightnotneedjquery.com/ * …...

帮别人做非法网站/媒体平台

matlab之基本绘图函数 clear&#xff1a;清空内存中的变量&#xff1b;figure:强制生成一个新的个绘图窗口&#xff1b;syms x y t :声明变量&#xff1b;fplot(函数表达式,绘图区间)&#xff1b;plot(横坐标向量&#xff0c;纵坐标向量&#xff0c;颜色/线形等参数)ezplot(函数…...

建设工程施工合同实例/百度seo排名

如果您不介意使用JavaScript和jQuery&#xff0c;则可以使用jQuery client plugin检测操作系统&#xff0c;然后设置字体。它似乎是旧东西&#xff0c;但它适用于jQuery 1.3.2&#xff0c;如果它适用于jQuery 1.6.1&#xff0c;我不会感到惊讶。if($.client.os Mac)$(body).cs…...

凡科企业网站如何建设/百度seo提高排名费用

转载请标明出处&#xff1a; http://blog.csdn.net/xx326664162/article/details/50902236 文章出自&#xff1a;薛瑄的博客 你也可以查看我的其他同类文章&#xff0c;也会让你有一定的收货&#xff01; 在资源文件里&#xff0c;可以这样写. <resources><string…...