前置背景
Glide 作为常用的图片加载框架,框架层面已经对内存方面有不少优化,但作为一个图片框架,确保正确性一定是第一位的,因此在应用层还可以在适当的场景做一些额外的优化,当然你需要了解优化设置可能产生的问题。另外框架设计复杂性是很高的,但暴露给上层的 API 又非常简单,这导致我们忽略一些基本的工作原理,从而有意无意错误的使用框架。
这不是一篇 Glide 源码分析类的文章,如果对 Glide 使用还不够熟悉,不建议直接阅读。 以下文档结论基于 Glide v4+ 版本。
Glide 的一些特性
- 在不经其他额外配置的情况下 Glide 加载到内存中的 bitmap 大小不会超过视图大小本身,因此不会存在内存浪费。例如,网络图片原图大小为 200x200,但显示在页面中的 ImageView 控件大小为 100x100,Glide 内部最终解码的图片大小为 100x100。
- 若网络图片大小 > 控件宽或高,则默认情况下会按比例放大,返回一个满足宽高比例的位图。
- Glide v4+ 开始图片加载回归 ARGB_8888 格式作为默认 DecodeFormat。
- 如果加载图片时使用 RGB_565 格式,则实际运行不一定能够生效,主要是受两方面影响:1是如果图片本身包含透明度则仍会使用 ARGB_8888 格式,2是包含一些圆角或关于Alpha 的 Transform 变换,也会保持 ARGB_8888 格式。
- 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 & 默认直角 | 12730 | 5410 |
RGB_565/ARGB_8888 & 圆角 Transform | 17326 | 6564 |
RGB_565 & CardView 圆角 | 13633 | 5417 |
可以看到是 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))
}
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
**因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
![img](https://img-blog.csdnimg.cn/img_convert/600c8b8ded074e895589c264b692aee4.png)
![img](https://img-blog.csdnimg.cn/img_convert/a15a8eece20e79abb492f10eea476e6c.png)
![img](https://img-blog.csdnimg.cn/img_convert/32efde413482fe17d80ccd9e187929d0.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!**
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新**
**如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)**
![img](https://img-blog.csdnimg.cn/img_convert/3cfa9df82bc1f683d04077f99e44995c.png)
**一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
(img-fciXVC6f-1712878816390)]
**一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**