从内存优化视角再看 Glide 图片加载库

news2024/10/5 19:19:39

前置背景

Glide 作为常用的图片加载框架,框架层面已经对内存方面有不少优化,但作为一个图片框架,确保正确性一定是第一位的,因此在应用层还可以在适当的场景做一些额外的优化,当然你需要了解优化设置可能产生的问题。另外框架设计复杂性是很高的,但暴露给上层的 API 又非常简单,这导致我们忽略一些基本的工作原理,从而有意无意错误的使用框架。

这不是一篇 Glide 源码分析类的文章,如果对 Glide 使用还不够熟悉,不建议直接阅读。 以下文档结论基于 Glide v4+ 版本。

Glide 的一些特性

  1. 在不经其他额外配置的情况下 Glide 加载到内存中的 bitmap 大小不会超过视图大小本身,因此不会存在内存浪费。例如,网络图片原图大小为 200x200,但显示在页面中的 ImageView 控件大小为 100x100,Glide 内部最终解码的图片大小为 100x100。
  2. 若网络图片大小 > 控件宽或高,则默认情况下会按比例放大,返回一个满足宽高比例的位图。
  3. Glide v4+ 开始图片加载回归 ARGB_8888 格式作为默认 DecodeFormat。
  4. 如果加载图片时使用 RGB_565 格式,则实际运行不一定能够生效,主要是受两方面影响:1是如果图片本身包含透明度则仍会使用 ARGB_8888 格式,2是包含一些圆角或关于Alpha 的 Transform 变换,也会保持 ARGB_8888 格式。
  5. Glide 占用系统哪部分的内存?从 Android 8.0 开始,Bitmap 内存分配在 Native 堆,在未开启硬件位图前,还会在硬件层复制一份位图的拷贝,因此是双倍内存。硬件位图特性从 Android O 版本开始,在不了解硬件位图弊端前,应该谨慎使用,详情参考:了解硬件位图 。由此,应用不会因为图片内存占用过高导致 OOM。

Glide 使用的一些细节点

手动设置 override(width, height) 时,要确保不要使用大于控件实际尺寸的 size。

手动调用 override 的方式,对于解码图片的大小优先级最高,会默认跳过采样策略计算,如果你明确知道显示区域需要多大的图片可以使用此方法,避免图片放大(第5条)。如果想使用原图大小,可以使用 override(Target.SIZE_ORIGINAL)。

使用 preload 预加载图片默认会 decode 原图大小

preload 相关API 是不需要指定 Target 的,Glide 内部会默认加载原图,如果想明确 UI 上需要的尺寸,需调用重载的方法 preload(int width, int height)定制图片尺寸。

ImageView 在布局文件中,避免设置不明确的 match_parent 作为宽高

Glide 解码图片时是不会考虑 ImageView 的 scale_type 属性的,来看这个例子:

<ImageView
    android:id="@+id/iv_cover_bg"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="centerCrop" />

由于图片设置了 centerCrop 属性,在直观看图片会按等比居中缩放,但由于 decode 发生在 scaleType 生效之前,因此使用 Glide 加载图片时会以 ImageView 的实际尺寸(即全屏) 的宽高来解码图片,由此产生了不必要的内存开销。

解决方案比较多,常规的可以提前通过原始图和容器宽高比,计算出实际需要显示的图片尺寸,并使用 override(width, height) 方法强制指定解码图片的大小。亦或前提知道图片的比例,可使用 layout_constraintDimensionRatio 约束 ImageView 控件的大小。

如果封面图有圆角需求,使用 CardView 的圆角属性会比 Glide rounderCorner 内存开销低。

原因是 Glide rounderCorner 发生在图片decode 之后,经一轮变换会产生一个新的位图(官方描述为所有基于BitmapTransformation 变换产生的位图会被存储在 BitmapPool 中,并最终按 LRU 算法释放),而 CardView 是通过canvas.drawRoundRect(mBoundsF, mRadius, mRadius, paint),drawRoundRect 会转化成一系列绘图指令到 GPU,不会在堆内存产生额外的内存开销。

以下是实验数据,在三种情况下做内存数据对比,前置条件是加载一张 750x750 大小的不带透明度的 jpeg 格式的网络图片。按常规来说,如果使用 ARGB_8888 格式解码,产生的内存开销为 750x750x4 = 2197 kb,如果使用 RGB_565 则能减少一半的内存开销。

场景Native Heap(KB)Graphics(KB)
RGB_565 & 默认直角127305410
RGB_565/ARGB_8888 & 圆角 Transform173266564
RGB_565 & CardView 圆角136335417

可以看到是 NativeHeap 有明显的降低,推测与RounderCorner 额外变换导致的位图临时开销有关,Graphics 降低 1M 左右与预期相符。

关注图片放大场景

在背景知识中提到如果原图比控件容器大,则会缩小图片,并不会导致内存浪费。但如果原图比容器小会发生什么呢?例如:原图为 100x100,但容器为 200x200,那么默认情况下 decode 出一个 200x200 的位图。事实上,Glide 整体的图片缩放机制是通过内部的 DownsampleStrategy 完成的,其内部定义了与 ScaleType 类似的采样策略,默认的采样策略为 CENTER_OUTSIDE: 当原图尺寸 < 控件尺寸时会成比例放大至控件大小。另外还有其他采样策略,使用 AT_LEAST、AT_MOST、CENTER_INSIDE 模式,当明确知道原图尺寸 < 控件尺寸时均不会放大原图;反之,当原图尺寸 > 控件尺寸是可能会出现解码出大于控件尺寸图的情况。

使用示例:

Glide.with(this)
    .asBitmap()
    .load(url)  
    .apply(RequestOptions.downsampleOf(DownsampleStrategy.AT_LEAST))
    .into(imageView)

RGB_565 模式不生效与 Alpha Transform 变换冲突问题。

有效降低内存,对于多图文或 Feed 列表的 App,开启该配置可降低 10-20M 内存。示例全局开启 RGB_565 解码配置。

@GlideModule
class GlideConfig : AppGlideModule() {

    override fun applyOptions(context: Context, builder: GlideBuilder) {
        super.applyOptions(context, builder)
        builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565))
    }
    ...
}

但与此同时你需要了解在一些情况下 RGB_565 可能不生效,甚至产生奇怪的显示效果。

  1. 若原图包含 alpha 透明度,则配置失效。
  2. RGB_565 配置与 RoundedCorners/CircleCrop 变换同时使用时,配置失效。
  3. RGB_565 与一些包含硬件绘制指令的变换同时使用时,配置失效或显示异常。

1/2 比较好理解,对于3,常见的就是高斯模糊效果(毛玻璃),该效果目前是通过 RenderScript 相关API,此 API 要求应用视图必须开启硬件加速。在此情况下,同时开启 RGB_565 配置会导致出现异常,可能会返回一个空的位图,在部分设备上可能会返回一个异常的模糊效果。

图片降质与内存优化没有必然关联

根据以上 Glide 对图片的缩放处理可知,默认情况下一张图片占用的最大内存只与控件宽/高和解码格式有关。

在整个图片处理的过程中,图片降质只是减少图片的下载速度,对内存占用并无直接影响。


为了帮助到大家更好的掌握好 开源框架相关知识点,这准备了 Android 开源框架的学习手册↓↓↓

有需要的可以复制下方链接,传送直达!!!
https://qr21.cn/CaZQLo?BIZ=ECOMMERCE

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1187399.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【2021研电赛】基于深度学习的蛋白质与化合物结合性质预测

本作品介绍参与极术社区的有奖征集|分享研电赛作品扩大影响力&#xff0c;更有重磅电子产品免费领取! 获奖情况&#xff1a;三等奖 1.作品简介 针对药物发现过程中的药物筛选问题&#xff0c;本设计基于深度学习提出新的神经网络结构和数据处理方式用于预测蛋白质与化合物之…

【C++】:内存管理:C++内存分布 || C++中动态内存管理(new || delete)

&#x1f4ed;1. C/C内存分布 【说明】 &#x1f0cf;1. 栈又叫堆栈–非静态局部变量/函数参数/返回值等等&#xff0c;栈是向下增长的 &#x1f0cf;2. 内存映射段是高效的I/O映射方式&#xff0c;用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存&#xff…

基于JavaWeb+SpringBoot+微信小程序的酒店商品配送平台系统的设计和实现

基于JavaWebSpringBoot微信小程序的酒店商品配送平台系统的设计和实现 源码传送入口前言主要技术系统设计功能截图Lun文目录订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码传送入口 前言 本章内容概括了基于微信小程序的酒店商品配送平台的可行性分析、系统功…

19.11 Boost Asio 获取远程目录

远程目录列表的获取也是一种很常用的功能&#xff0c;通常在远程控制软件中都存在此类功能&#xff0c;实现此功能可以通过filesystem.hpp库中的directory_iterator迭代器来做&#xff0c;该迭代器用于遍历目录中的文件和子目录&#xff0c;它允许开发者轻松遍历目录层次结构并…

智能文件改名:高效复制并删除冗余,简化文件管理“

在繁杂的电脑文件世界中&#xff0c;如何高效地管理文件成为了许多人的难题。为了解决这一难题&#xff0c;我们推出了一款智能文件改名工具&#xff0c;它能够轻松复制文件并删除目标文件夹中的冗余文件&#xff0c;让您的文件管理更加高效便捷。 第一步&#xff0c;我们要打…

2.4 - 网络协议 - TCP协议工作原理,报文格式,抓包实战,UDP报文,UDP检错原理

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 TCP协议 1、TCP协议工作原理2、TCP协议报文格式3、…

win 命令替代鼠标的操作

操作方式都是在 winR 输入框输入或者终端输入 1、快速打开 控制面板 运行control 2、快速打开 电源选项 运行powercfg.cpl 3、快速打开 网络连接 运行ncpa.cpl 4、快速打开 程序和功能 运行appwiz.cpl 5、快速打开 Windows Defender防火墙 运行Firewall.cpl 6、快速打开 鼠标 …

华为gre带验证key案例

配置FW_A。 a.配置接口的IP地址&#xff0c;并将接口加入安全区域。 system-view [sysname] sysname FW_A [FW_A] interface GigabitEthernet 1/0/1 [FW_A-GigabitEthernet1/0/1] ip address 1.1.1.1 24 [FW_A-GigabitEthernet1/0/1] quit [FW_A] interface GigabitEthernet 1/…

Web前端—CSEO、Favicon、小兔鲜儿电商网站顶部设计

版本说明 当前版本号[20231108]。 版本修改说明20231108初版 目录 文章目录 版本说明目录电商平台网站顶部设计项目目录准备工作SEO 三大标签Favicon 图标布局网页版心快捷导航&#xff08;shortcut&#xff09;头部&#xff08;header&#xff09;logo导航搜索购物车 电商平…

【C语言基础】第02章_变量与进制

讲师&#xff1a;康师傅 视频&#xff1a;https://www.bilibili.com/video/BV1Bh4y1q7Nt?p1&vd_source3eaa9d17f2454e1ae80abc50d16e66b5 文章目录 本章专题脉络1关键字(keyword)2标识符(Identifier)3变量(variable)3.1 为什么需要变量3.2 初识变量3.3 变量的声明与赋值步…

从TCP到Socket,彻底理解网络编程是怎么回事

进行程序开发的同学&#xff0c;无论Web前端开发、Web后端开发&#xff0c;还是搜索引擎和大数据&#xff0c;几乎所有的开发领域都会涉及到网络编程。比如我们进行Web服务端开发&#xff0c;除了Web协议本身依赖网络外&#xff0c;通常还需要连接数据库&#xff0c;而数据库连…

网络原理---拿捏数据链路层:以太网

文章目录 目的地址、源地址类型CRC帧尾&#xff1a;校验和 学习协议很大程度上就是学习协议的报文格式&#xff0c;下面就来介绍以太网的报文格式&#xff1a; 目的地址、源地址 这个地址是mac地址&#xff0c;是用6个字节表示的地址。它也是用来标识主机位置的&#xff0c;但…

【ES专题】Logstash与FileBeat详解以及ELK整合详解

目录 前言阅读对象阅读导航前置知识笔记正文一、ELK架构1.1 经典的ELK1.2 整合消息队列Nginx架构 二、LogStash介绍2.1 Logstash核心概念2.1.1 Pipeline2.1.2 Event2.1.3 Codec (Code / Decode)2.1.4 Queue 2.2 Logstash数据传输原理2.3 Logstash的安装&#xff08;以windows为…

【解决问题】---- 解决 avue-crud 表格勾选数据翻页后界面保持选中

1. 错误预览 第一页选择【7、8、9、10】 直接点击第三页未进行选择 直接点击第四页未进行选择 2. 问题总结 通过测试可以看到&#xff0c;页面的选择项会影响到其他页面的选择&#xff1b;点击保存&#xff0c;返回的数据却是真真选择的数据&#xff1b;数据在选择渲染…

Leetcode—515.在每个树行中找最大值【中等】

2023每日刷题&#xff08;二十三&#xff09; Leetcode—515.在每个树行中找最大值 DFS实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ /*** Note: The returned arra…

rhcsa-用户和组管理

一.用户和组的分类 1、在Linux中用户可以分为三类 第一种是超级用户一一用户名为root&#xff0c;它具有一切权限&#xff0c;只有进行系统维护(例如:建立用户等)或其他必要情形下才用超级用户登录&#xff0c;以避免系统出现安全问题 第二种是系统用户(伪用户)一一是…

2—C++程序设计:C++简单程序设计

2—C程序设计&#xff1a;C简单程序设计 1&#xff0c;无符号数的32bits系统的运算二级目录三级目录 1&#xff0c;无符号数的32bits系统的运算 32位系统&#xff0c; 1&#xff0c;有符号数的范围是&#xff1a;0~4, 294, 967, 295&#xff1b; 2&#xff0c;无符号数的范围是…

Java中对象转型

理解&#xff1a; 有一个对象 new ADHero(), 同时也有一个引用ad 对象是有类型的&#xff0c; 是ADHero 引用也是有类型的&#xff0c;是ADHero 一般来说引用类型和对象类型是一样的&#xff0c;当引用类型和对象类型不一致就要考虑类型转换 简单判断&#xff1a;把右边的当…

osg 八叉树可视化

目录 什么是八叉树 八叉树算法过程 八叉树的计算原理 八叉树c实现 使用osg可视化八叉树 什么是八叉树 在描述三维场景的过程中常常用到一种名为八叉树的数据结构。描述三维空间的八叉树和描述二维空间的四叉树有相似之处&#xff0c;二维空间中正方形可以被分为四个相同形…

3.29每日一题(微分方程的几何应用题:重点考察)

1、画图&#xff0c;把题目中的条件标出来 2、通过题目中的条件设出正确的微分方程&#xff08;解题的关键&#xff09; 注&#xff1a;用点斜式设方程的时候&#xff0c;注意Y - y y&#xff08;X - x&#xff09;中&#xff08;x&#xff0c;y&#xff09;为曲边上的动点&a…