文章目录
- 第一部分:基础核心
-
- [1. Glide 是什么?结合实际开发,说说它解决了安卓图片加载的哪些痛点?](#1. Glide 是什么?结合实际开发,说说它解决了安卓图片加载的哪些痛点?)
- [2. 实际开发中,Glide 加载一张网络图片的完整流程(结合缓存、解码、展示)](#2. 实际开发中,Glide 加载一张网络图片的完整流程(结合缓存、解码、展示))
- [3. 实际开发中,为什么不建议用 Glide.with(Application) 加载图片?举2个实际场景说明危害](#3. 实际开发中,为什么不建议用 Glide.with(Application) 加载图片?举2个实际场景说明危害)
- 第二部分:缓存机制(高频核心,结合开发场景)
-
- [1. 实际开发中,Glide 三级缓存的作用的是什么?分别对应哪些开发场景?](#1. 实际开发中,Glide 三级缓存的作用的是什么?分别对应哪些开发场景?)
- [2. Glide的磁盘缓存策略对比](#2. Glide的磁盘缓存策略对比)
- [3. 实际开发中,遇到"图片 URL 不变,但内容更新"的场景,如何用 Glide 实现强制刷新?(举2种常用方案,说明优缺点)](#3. 实际开发中,遇到“图片 URL 不变,但内容更新”的场景,如何用 Glide 实现强制刷新?(举2种常用方案,说明优缺点))
- [4. 三种缓存对比](#4. 三种缓存对比)
- [第三部分:内存优化与 Bitmap 复用(高级必问,贴合OOM排查)](#第三部分:内存优化与 Bitmap 复用(高级必问,贴合OOM排查))
-
- [1. 实际开发中,Glide 防止 OOM 的核心机制有哪些?结合具体场景说明(如列表多图、大图加载)](#1. 实际开发中,Glide 防止 OOM 的核心机制有哪些?结合具体场景说明(如列表多图、大图加载))
- [2. 实际开发中,遇到"Glide 加载大图仍出现 OOM",排查思路是什么?(结合具体排查步骤)](#2. 实际开发中,遇到“Glide 加载大图仍出现 OOM”,排查思路是什么?(结合具体排查步骤))
- [3. 实际开发中,BitmapPool 复用失效的常见原因有哪些?如何解决?](#3. 实际开发中,BitmapPool 复用失效的常见原因有哪些?如何解决?)
- 第四部分:生命周期与请求管理(进阶,贴合页面开发)
-
- [1. 实际开发中,Glide 如何实现"页面退到后台,暂停图片加载;回到前台,恢复加载"?原理是什么?](#1. 实际开发中,Glide 如何实现“页面退到后台,暂停图片加载;回到前台,恢复加载”?原理是什么?)
- [2. 实际开发中,RecyclerView 滑动时,如何优化 Glide 加载体验?(结合滑动卡顿、图片闪烁问题)](#2. 实际开发中,RecyclerView 滑动时,如何优化 Glide 加载体验?(结合滑动卡顿、图片闪烁问题))
- [3. 实际开发中,preload() 和 thumbnail() 的使用场景有哪些?举例说明](#3. 实际开发中,preload() 和 thumbnail() 的使用场景有哪些?举例说明)
- 第五部分:扩展与自定义(架构级,贴合复杂项目)
-
- [1. 实际开发中,如何自定义 Glide 变换(Transformation)?举一个实际场景(如圆形头像)说明步骤:](#1. 实际开发中,如何自定义 Glide 变换(Transformation)?举一个实际场景(如圆形头像)说明步骤:)
- [2. 实际开发中,如何用 Glide 加载加密图片?(如后台返回加密的图片流,需解密后展示)](#2. 实际开发中,如何用 Glide 加载加密图片?(如后台返回加密的图片流,需解密后展示))
- [3. 实际开发中,AppGlideModule 的常用配置有哪些?结合项目场景说明](#3. 实际开发中,AppGlideModule 的常用配置有哪些?结合项目场景说明)
- 第六部分:源码与架构设计(大厂深度,贴合底层理解)
-
- [1. 结合实际开发,说说 Glide 引擎(Engine)的核心作用?加载流程中,Engine 如何协调缓存和请求?](#1. 结合实际开发,说说 Glide 引擎(Engine)的核心作用?加载流程中,Engine 如何协调缓存和请求?)
- [2. Glide 为什么要区分"网络线程池、磁盘线程池、解码线程池"?结合实际开发说明好处](#2. Glide 为什么要区分“网络线程池、磁盘线程池、解码线程池”?结合实际开发说明好处)
- [3. 实际开发中,Glide 加载图片出现"拉伸、变形"的常见场景及解决方案?](#3. 实际开发中,Glide 加载图片出现“拉伸、变形”的常见场景及解决方案?)
- [4. 线上排查"Glide 导致的内存泄漏",常见原因及排查方案?(结合 LeakCanary 工具)](#4. 线上排查“Glide 导致的内存泄漏”,常见原因及排查方案?(结合 LeakCanary 工具))
- [5. 实际开发中,Glide 加载速度优化的完整方案?(结合弱网、大图、列表等场景)](#5. 实际开发中,Glide 加载速度优化的完整方案?(结合弱网、大图、列表等场景))
- [6. 实际开发中,Glide 加载 GIF 出现卡顿、内存上涨的原因及解决方案?](#6. 实际开发中,Glide 加载 GIF 出现卡顿、内存上涨的原因及解决方案?)
- [7. 结合你做过的项目,说说 Glide 遇到的最棘手的问题是什么?如何解决的?(贴合真实项目)](#7. 结合你做过的项目,说说 Glide 遇到的最棘手的问题是什么?如何解决的?(贴合真实项目))
第一部分:基础核心
1. Glide 是什么?结合实际开发,说说它解决了安卓图片加载的哪些痛点?
Glide 是 Google 推荐的 Android 图片加载框架,专注于图片的获取、解码、缓存和展示,核心解决安卓开发中图片加载的核心痛点:
- 解决 OOM 问题:实际开发中加载大图、多图(如列表)时,频繁创建 Bitmap 易导致内存溢出,Glide 通过 Bitmap 复用、自动下采样等机制,大幅降低 OOM 概率;
- 解决加载效率低问题:实际开发中图片来源多样(网络、本地、资源),Glide 三级缓存机制(内存+磁盘+网络),避免重复请求,提升加载速度(如列表滑动时快速复用缓存);
- 解决内存泄漏问题:开发中常出现页面销毁后图片请求仍在执行,导致 Activity 泄漏,Glide 自动绑定页面生命周期,页面销毁时取消请求,避免泄漏;
- 解决适配问题:不同机型、不同 ImageView 尺寸差异大,Glide 自动根据目标尺寸计算采样率,无需手动处理,避免图片拉伸、模糊;
- 解决复杂场景需求:实际开发中需支持 GIF 播放、图片裁剪(圆角/圆形)、缩略图加载等,Glide 内置相关能力,无需重复开发
2. 实际开发中,Glide 加载一张网络图片的完整流程(结合缓存、解码、展示)
- 绑定生命周期:通过 Glide.with(Activity/Fragment) 绑定页面生命周期,确保页面销毁时能取消请求;
- 发起请求:通过 load(url) 指定网络图片地址,apply() 设置缓存策略、占位图、裁剪方式等配置;
- 缓存查询 :优先查询内存缓存 (正在使用的 ActiveResources → 闲置的 LruResourceCache),命中则直接解码展示;内存未命中则查询磁盘缓存(优先查处理后的 RESULT 缓存,再查原始 SOURCE 缓存),命中则解码后存入内存并展示;
- 网络请求:缓存均未命中时,发起网络请求下载图片,下载完成后,先写入磁盘缓存(SOURCE+RESULT),再解码为 Bitmap;
- 图片处理与展示:解码后的 Bitmap 经过预设的变换(如圆角),存入内存缓存,最终展示到 ImageView;
- 异常处理:若网络请求失败,展示错误占位图,同时可通过监听回调记录异常(用于线上排查)
3. 实际开发中,为什么不建议用 Glide.with(Application) 加载图片?举2个实际场景说明危害
核心原因:Application 是全局生命周期,Glide 无法绑定页面生命周期,会导致无效请求和内存泄漏 ,实际开发中常见危害场景:
场景1 :列表页加载图片,用户快速跳转页面(如从列表页跳详情页),若用 Application 上下文,列表页的图片请求不会随页面销毁而取消,会继续下载、解码,浪费流量和内存,甚至导致页面切换卡顿;
场景2 :详情页加载一张超大图,用户看完后返回上一页(详情页销毁),若用 Application 上下文,大图请求仍在执行,Bitmap 加载完成后无法及时释放,易导致 OOM,尤其在低内存机型上更明显;
例外场景:全局通用的图片(如 App 图标),可使用 Application 上下文,避免频繁创建 RequestManager。
第二部分:缓存机制(高频核心,结合开发场景)
1. 实际开发中,Glide 三级缓存的作用的是什么?分别对应哪些开发场景?
Glide 三级缓存(活动缓存→内存缓存→磁盘缓存),核心作用是减少重复请求、提升加载速度、降低内存/流量消耗,对应实际开发场景如下:
- 活动缓存(ActiveResources):存储正在页面中显示的图片,弱引用持有,避免正在显示的图片被 LRU 回收(场景:列表滑动时,当前可见的 Item 图片,不会被内存回收,避免重新加载导致闪烁);
- 内存缓存(LruResourceCache):LRU 策略缓存闲置的、已解码的 Bitmap(场景:列表滑动时,滑动过的 Item 图片,再次滑动到可见区域时,无需查磁盘/网络,直接从内存读取,提升滑动流畅度);
- 磁盘缓存(DiskLruCache) :缓存原始图片(SOURCE)和处理后图片(RESULT)(场景:App 重启后,无需重新请求网络,从磁盘读取图片,减少流量消耗;弱网/离线场景下,仍能展示图片)。
速记版答案
活动缓存:正在显示,防闪烁;内存缓存:闲置图片,提流畅;磁盘缓存:持久化,省流量、支持离线。
2. Glide的磁盘缓存策略对比

3. 实际开发中,遇到"图片 URL 不变,但内容更新"的场景,如何用 Glide 实现强制刷新?(举2种常用方案,说明优缺点)
实际开发中常见场景:用户更新头像(URL 不变,图片内容变化)、后台更新图片(URL 不变),两种常用方案及优缺点如下:
- 方案1:跳过缓存(简单直接)
用法:Glide.with(context).load(url).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.NONE).into(imageView);
优点:代码简单,无需额外处理,能快速获取最新图片;
缺点:每次都要发起网络请求,浪费流量,加载速度慢,不适合频繁刷新的场景; - 方案2:使用 Signature 签名(推荐,兼顾刷新和缓存)
用法:结合图片版本号、时间戳或 MD5,如Glide.with(context).load(url).signature(ObjectKey(version)).into(imageView);(version 由后台返回,图片更新时 version 变化);
优点:图片更新时(version 变化),生成新的缓存 Key,重新请求并缓存;图片未更新时,正常使用缓存,节省流量和时间;
缺点:需要后台配合返回版本号/时间戳,略增加开发成本。
速记版答案
方案1:skipMemoryCache+NONE 缓存,简单但费流量;方案2:Signature+版本号,推荐,兼顾缓存和刷新。
4. 三种缓存对比

第三部分:内存优化与 Bitmap 复用(高级必问,贴合OOM排查)
1. 实际开发中,Glide 防止 OOM 的核心机制有哪些?结合具体场景说明(如列表多图、大图加载)
Glide 防止 OOM 的核心机制,均贴合实际开发中高频 OOM 场景(列表多图、大图加载、GIF 加载),具体如下:
- Bitmap 复用池(BitmapPool):核心机制,场景:列表多图加载时,频繁创建/销毁 Bitmap 会导致内存碎片,Glide 复用池缓存可复用的 Bitmap,加载新图时优先复用,减少内存分配(如 RecyclerView 滑动加载大量图片,复用池大幅降低 OOM 概率);
- 自动下采样(Downsampling):场景:加载大图(如相机拍摄的图片、后台返回的超大图),Glide 自动根据 ImageView 尺寸计算采样率(inSampleSize),不加载完整尺寸,减少 Bitmap 内存占用(如 1080P 大图,ImageView 尺寸为 400x400,采样后内存减少约 6 倍);
- 默认 RGB_565 配置:场景:普通图片(无需透明通道),RGB_565 比 ARGB_8888 内存减少一半,无明显画质损失,适合列表、Banner 等场景;
- 生命周期自动取消:场景:页面销毁(如用户跳转、退后台),Glide 自动取消图片请求,释放 Bitmap,避免内存泄漏导致 OOM;
- 内存缓存限制:通过 LRU 策略,当内存缓存达到阈值时,回收最少使用的图片,避免内存占用超限。
2. 实际开发中,遇到"Glide 加载大图仍出现 OOM",排查思路是什么?(结合具体排查步骤)
- 检查是否指定图片尺寸 :排查是否未使用
override()指定目标尺寸,导致 Glide 加载原图(如 4K大图,未指定尺寸,直接加载会占用大量内存),解决方案:根据 ImageView 实际尺寸,用 override(width,height) 限制; - 检查 Bitmap 配置 :排查是否强制使用 ARGB_8888 配置(如图片无需透明通道,仍用该配置),解决方案:开启
allowRgb565(true),切换为 RGB_565,减少一半内存; - 检查 Bitmap 复用是否生效 :排查是否自定义 Transformation 未复用 Bitmap,频繁创建新 Bitmap,解决方案:在变换中复用 BitmapPool 中的对象,避免手动 new Bitmap;
- 检查生命周期绑定 :排查是否使用 Application 上下文加载大图,页面销毁后请求未取消,解决方案:改用页面级 Context(Activity/Fragment);
- 检查缓存设置:排查是否内存缓存设置过大,导致内存占用超限,解决方案:通过 AppGlideModule 调整内存缓存大小,或在大图加载时跳过内存缓存
速记版答案
查尺寸(override)→ 查配置(RGB_565)→ 查复用 → 查生命周期 → 查缓存设置。
3. 实际开发中,BitmapPool 复用失效的常见原因有哪些?如何解决?
BitmapPool 复用的核心条件是"宽高足够、Config 一致",实际开发中复用失效的常见原因及解决方案如下:
- Config 不匹配(最常见) :原因:复用池中的 Bitmap 是 RGB_565,而新请求的图片是
ARGB_8888(如加载带透明通道的图片),无法复用;解决方案:根据图片需求,统一 Config,或在请求时指定 Config,确保与复用池一致; - 宽高不足:原因:复用池中的 Bitmap 尺寸小于新请求图片的目标尺寸(如复用池中有 400x400 的 Bitmap,新图片目标尺寸是 500x500),无法复用;解决方案:加载图片时,用 override() 指定合理尺寸,或调整复用池大小,缓存更大尺寸的 Bitmap;
- API 版本限制:原因:低版本机型(API 19 以下),复用要求宽高完全一致,而新请求图片尺寸与复用池中的不一致;解决方案:适配低版本,要么统一图片尺寸,要么放弃低版本复用,优先保证功能;
- 自定义 Transformation 破坏复用:原因:自定义变换时,手动创建新 Bitmap,未从 BitmapPool 中获取,导致复用失效;解决方案:在变换中通过 BitmapPool.obtain() 获取可复用 Bitmap,使用后释放回池中
速记版答案
原因:Config 不匹配、宽高不足、API 版本、自定义变换未复用;解决:统一 Config、指定尺寸、适配低版本、变换复用 BitmapPool。
第四部分:生命周期与请求管理(进阶,贴合页面开发)
1. 实际开发中,Glide 如何实现"页面退到后台,暂停图片加载;回到前台,恢复加载"?原理是什么?
实际开发中,为了节省流量和内存,需实现"后台暂停、前台恢复",Glide 自动支持该功能,原理结合生命周期绑定:
- 实现方式 :无需额外代码,
Glide.with(Activity/Fragment)绑定页面生命周期后,自动监听页面的 onStart()和 onStop() 方法; - 原理 :Glide 通过 RequestManager 来管理图片加载请求,它会根据传入的 Activity 或 Fragment 生命周期自动绑定并监听状态变化 :
页面退到后台(onStop():触发 onStop(),Glide 暂停所有图片请求,避免后台继续下载、解码,节省流量和内存;
页面回到前台(onStart(): 触发 onStart(),Glide 恢复暂停的请求,继续加载图片,保证页面展示正常; - 特殊场景:若用 Application 上下文,无法实现该功能,需手动调用 pauseRequests() 和 resumeRequests() 控制。
2. 实际开发中,RecyclerView 滑动时,如何优化 Glide 加载体验?(结合滑动卡顿、图片闪烁问题)
- 滑动时暂停请求,停止时恢复 :在 RecyclerView 的
onScrollStateChanged
方法中,判断滑动状态,滑动时(SCROLL_STATE_SCROLLING)调用Glide.with(context).pauseRequests(),停止滑动时(SCROLL_STATE_IDLE)调用
resumeRequests(),避免滑动时大量请求导致卡顿; - 避免图片闪烁 :原因是滑动时占位图与缓存图切换、过渡动画导致 ,解决方案:关闭过渡动画(dontAnimate()),去掉占位图(或使用与图片底色一致的占位图),确保缓存命中率(diskCacheStrategy(ALL))
- 复用 ViewHolder 时清空 ImageView :在 onBindViewHolder 中,先调用
Glide.clear(imageView),避免复用 View 时,旧图片未加载完成,新图片开始加载,导致图片错乱; - 限制图片尺寸 :用
override()指定与 Item 尺寸一致的图片尺寸,减少解码耗时,避免滑动卡顿; - 避免复杂变换 :滑动时,避免在主线程执行复杂变换(如高斯模糊),可提前缓存变换后的图片,或在子线程执行变换。
速记版答案
滑动暂停请求、关闭动画/去掉占位、清空 ImageView、指定尺寸、避免复杂变换
3. 实际开发中,preload() 和 thumbnail() 的使用场景有哪些?举例说明
preload() 和 thumbnail() 都是 Glide 的预加载相关方法,适用场景不同,实际开发中典型场景如下:
- preload():只加载到缓存,不显示,用于"提前缓存后续需要展示的图片",提升后续加载速度 ;
场景1:启动页预加载首页图片,用户进入首页后,图片可直接从缓存加载,避免白屏;
场景2:列表页预加载下一页图片,用户滑动到下一页时,图片已缓存,提升滑动流畅度; - thumbnail():先加载低分辨率缩略图,再替换为高清原图,用于"优化大图加载体验",减少白屏时间 ;
场景1:详情页加载超大图(如商品详情图),弱网环境下,先显示缩略图,再加载原图,避免用户长时间等待白屏;
场景2:朋友圈图片加载,先显示模糊缩略图,再加载清晰原图,提升用户体验
速记版答案
preload:提前缓存(启动页、列表下一页);thumbnail:大图渐进加载(详情页、朋友圈)。
第五部分:扩展与自定义(架构级,贴合复杂项目)
1. 实际开发中,如何自定义 Glide 变换(Transformation)?举一个实际场景(如圆形头像)说明步骤:
实现 BitmapTransformation 抽象类 ,重写两个核心方法:transform()(实现圆形裁剪逻辑)、updateDiskCacheKey()(更新缓存 Key,避免缓存冲突
- 使用方式 :
Glide.with(context).load(url).apply(RequestOptions.bitmapTransform(new CircleTransformation())).into(imageView); - 优化 :将自定义变换封装为单例 ,避免频繁创建;在变换中复用 BitmapPool,减少内存占用。
速记版答案
步骤:实现 BitmapTransformation → 重写 transform(绘制圆形)和 updateDiskCacheKey(唯一 Key)→ 复用 BitmapPool → 调用使用;场景:圆形头像。
2. 实际开发中,如何用 Glide 加载加密图片?(如后台返回加密的图片流,需解密后展示)
- 自定义数据模型:创建 EncryptImageModel 类,封装加密图片的 URL、解密密钥等信息;
- 实现 DataFetcher:负责获取加密图片流,并进行解密,重写 loadData()(发起网络请求获取加密流,解密为普通输入流)、cleanup()(释放资源)、cancel()(取消请求);
- 实现 ModelLoader :将
EncryptImageModel转换为解密后的输入流,重写buildLoadData()(返回自定义 DataFetcher)、handles()(判断是否处理该模型); - 注册组件 :在
AppGlideModule的registerComponents()方法中,通过registry.append(EncryptImageModel.class, InputStream.class, new EncryptModelLoader.Factory())注册自定义 ModelLoader; - 使用方式 :
Glide.with(context).load(new EncryptImageModel(url, key)).into(imageView);
注意:解密过程需在子线程执行,避免阻塞主线程;解密后的输入流需正确关闭,避免资源泄漏。
速记版答案
步骤:自定义加密模型 → 实现 DataFetcher(解密)→ 实现 ModelLoader → 注册 → 加载;核心:解密在子线程,释放资源
3. 实际开发中,AppGlideModule 的常用配置有哪些?结合项目场景说明
- 配置内存缓存大小 :场景:项目中图片较多(如电商 App),默认内存缓存不足,易导致频繁回收,配置:
builder.setMemoryCache(new LruResourceCache(内存大小)); - 配置磁盘缓存大小和路径 :场景:项目需限制磁盘缓存占用,或自定义缓存路径(如 SD 卡),配置:
builder.setDiskCache(new InternalCacheDiskCacheFactory(context, 缓存大小, 缓存路径)); - 注册自定义组件 :场景:加载加密图片、自定义变换,配置:
registry.append()注册ModelLoader,registry.register()注册Transformation; - 配置默认请求选项 :场景:全局统一图片配置(如默认 RGB_565、默认缓存策略 ),配置
builder.setDefaultRequestOptions(RequestOptions().allowRgb565(true).diskCacheStrategy(DiskCacheStrategy.ALL)); - 配置线程池 :场景:项目中图片加载并发量高 ,需调整线程池大小,配置:
builder.setSourceExecutor()(网络线程池)、builder.setDecodeExecutor()(解码线程池)
速记版答案
常用配置:内存/磁盘缓存、注册自定义组件、默认请求选项、线程池;贴合电商、加密图片等场景。
第六部分:源码与架构设计(大厂深度,贴合底层理解)
1. 结合实际开发,说说 Glide 引擎(Engine)的核心作用?加载流程中,Engine 如何协调缓存和请求?
Engine 是 Glide 的核心引擎,负责协调缓存查询、请求发起、解码、资源管理,是连接缓存和展示的核心,结合实际开发(如列表图片加载),其作用和协调逻辑如下:
- 核心作用:统一管理图片加载的全流程,避免重复请求,提升加载效率,同时控制内存和资源占用;
- 缓存与请求协调流程(贴合列表加载场景):
- 当发起图片请求时,Engine 先查询活动缓存(ActiveResources),若命中(当前可见的 Item 图片),直接返回资源,避免重复加载;
- 活动缓存未命中,查询内存缓存(LruResourceCache),若命中,将资源移到活动缓存,返回资源(如滑动过的 Item 图片,再次加载时从内存缓存获取);
- 内存缓存未命中,查询磁盘缓存,若命中,将资源解码后存入内存缓存和活动缓存,返回资源(如 App 重启后,加载之前缓存的图片);
- 磁盘缓存未命中,Engine 发起网络请求(通过 SourceExecutor 线程池),下载完成后,写入磁盘缓存,解码后存入内存缓存,返回资源;
- 关键优化:Engine 会对相同 URL 的请求进行合并(如列表中多个相同图片),避免重复发起请求,节省资源
2. Glide 为什么要区分"网络线程池、磁盘线程池、解码线程池"?结合实际开发说明好处
Glide 内置 3 种线程池,分别处理不同任务,核心原因是"隔离任务类型,避免互相阻塞,提升加载流畅度",结合实际开发好处如下:
- 线程池分工(贴合任务类型):
- 网络线程池(SourceExecutor):处理网络请求(IO 密集型任务),核心线程数 4,适合大量并发 IO 操作;
- 磁盘线程池(DiskExecutor):处理磁盘读写(IO 密集型任务),核心线程数 4,与网络线程池隔离;
- 解码线程池(DecodeExecutor):处理图片解码(CPU 密集型任务),核心线程数 = CPU 核心数,避免占用过多 CPU 资源;
- 实际开发好处:
- 避免 IO 阻塞 CPU:若网络/磁盘 IO 与解码共用一个线程池,当网络请求缓慢(如弱网),会阻塞解码任务,导致图片加载卡顿(如列表滑动时,解码被阻塞,图片无法及时展示);
- 提升并发效率:不同类型任务分开处理,网络请求、磁盘读写、解码可同时进行,如加载图片时,网络下载的同时,可解码已缓存的其他图片;
- 控制资源占用:解码线程池绑定 CPU 核心数,避免解码任务占用过多 CPU,导致 App 卡顿、ANR(如同时解码多张大图,CPU 占用过高)
3. 实际开发中,Glide 加载图片出现"拉伸、变形"的常见场景及解决方案?
- 场景1:ImageView 尺寸设置不合理(最常见)
原因 :ImageView 宽高设置为 wrap_content ,而图片尺寸与父布局不匹配 ;或宽高比与图片原始宽高比不一致;
解决方案:固定 ImageView 宽高,或设置宽高比(如用 ConstraintLayout 约束),结合 centerCrop()/fitCenter() 裁剪策略; - 场景2:未设置裁剪策略
原因 :图片原始宽高比与 ImageView 宽高比不一致 ,未设置裁剪策略,Glide 默认拉伸填充;
解决方案:根据需求设置 centerCrop()(填充裁剪,不拉伸)或 fitCenter()(适应屏幕,不裁剪 - 场景3:override() 设置尺寸与 ImageView 尺寸不匹配
原因 :用 override() 指定的尺寸,与 ImageView 实际显示尺寸不一致 ,导致图片拉伸;
解决方案:override() 尺寸与 ImageView 宽高保持一致,或使用 Target.SIZE_ORIGIN 结合裁剪策略; - 场景4:图片尺寸过小,被强行拉大
原因 :后台返回的图片尺寸过小,而 ImageView 尺寸较大,Glide 自动拉伸图片,导致模糊、变形;
解决方案:让后台返回适配尺寸的图片,或使用 centerCrop() 裁剪,避免拉伸。
速记版答案
场景:ImageView 尺寸不合理、未设裁剪、override 不匹配、图片尺寸过小;解决:固定尺寸、设 centerCrop/fitCenter、匹配 override 尺寸
4. 线上排查"Glide 导致的内存泄漏",常见原因及排查方案?(结合 LeakCanary 工具)
实际开发中,Glide 导致的内存泄漏,线上排查需结合 LeakCanary 工具,常见原因及排查方案如下:
- 常见泄漏原因(贴合线上场景):
- 原因1:使用 Application 上下文 加载图片,页面销毁后,请求未取消,Bitmap 引用持有 Activity 实例;
- 原因2:自定义 Target/RequestListener 中,持有 Activity/Fragment 的强引用,未及时释放;
- 原因3:RecyclerView 中,Glide 未及时 clear 图片请求,ViewHolder 被复用,导致引用泄漏;
- 原因4:GIF 加载时,无限循环播放,持有页面引用,页面销毁后未停止播放;
- 线上排查方案:
- 步骤1:集成 LeakCanary 工具,监控线上内存泄漏,获取泄漏堆栈;
- 步骤2:根据堆栈,判断是否与 Glide 相关(如出现 Glide 相关类:RequestManager、Target 等);
- 步骤3:定位泄漏原因:若堆栈显示 Activity 被 RequestManager 持有,大概率是用了 Application 上下文;若显示被 Target 持有,检查 Target 是否持有强引用;
- 步骤4:修复方案:改用页面级 Context 、用弱引用持有页面实例、在页面销毁时 clear 所有 Glide 请求、GIF 播放时监听生命周期,页面销毁停止播放。
5. 实际开发中,Glide 加载速度优化的完整方案?(结合弱网、大图、列表等场景)
- 缓存优化(核心,提升重复加载速度):
- 合理选择磁盘缓存策略(如普通图片用 ALL,头像用 SOURCE);
- 预加载关键图片(启动页预加载首页图片、列表预加载下一页);
- 调整内存缓存大小,提升内存命中率;
- 图片本身优化(减少加载/解码耗时):
- 与后台配合,使用 WebP/AVIF 格式(相同画质下,体积减少 50% 以上);
- 后台根据设备尺寸,返回适配尺寸的图片,避免客户端二次裁剪;
- 大图加载用 override() 指定合理尺寸,开启自动下采样;
- 线程与请求优化:
- 调整线程池大小,适配设备 CPU 核心数;
- 弱网环境下,使用 thumbnail() 加载缩略图,提升体验;
- 列表滑动时暂停请求,避免并发过多导致卡顿;
- 解码与复用优化:
- 普通图片开启 RGB_565,减少解码耗时和内存占用;
- 确保 BitmapPool 复用生效,减少 Bitmap 创建耗时;
- 异常处理优化:
- 弱网/离线场景下,优先展示磁盘缓存图片,避免白屏;
- 失败重试机制,避免单次网络波动导致加载失败。
6. 实际开发中,Glide 加载 GIF 出现卡顿、内存上涨的原因及解决方案?
GIF 加载是 Glide 的高频场景,易出现卡顿、内存上涨,结合实际开发原因及解决方案如下:
- 卡顿原因及解决:
- 原因1:GIF 帧数过多、分辨率过高,解码和渲染耗时,导致主线程卡顿 ;
- 解决:后台压缩 GIF(减少帧数、降低分辨率),客户端用 override() 限制尺寸,开启硬件加速;
- 原因2:GIF 渲染在主线程执行,占用过多 CPU ;
- 解决:使用 Glide 的 asGif() 方法,确保渲染在子线程执行,避免阻塞主线程;
- 内存上涨原因及解决:
- 原因1:GIF 每帧都是一个 Bitmap,帧数过多导致内存占用持续上涨 ;
- 解决:限制 GIF 循环次数(如 loop(1)),避免无限循环;页面销毁时,用 Glide.clear() 停止播放,释放帧资源;
- 原因2:GIF 帧未复用,每帧都创建新 Bitmap ;
- 解决:确保 Glide BitmapPool 复用生效,GIF 帧会优先复用池中的 Bitmap,减少内存分配;
- 特殊优化:弱网环境下,先加载 GIF 第一帧作为占位图,再加载完整 GIF,提升体验。
7. 结合你做过的项目,说说 Glide 遇到的最棘手的问题是什么?如何解决的?(贴合真实项目)
结合电商 App 项目(高频图片场景),最棘手的问题:RecyclerView 列表滑动时,图片加载卡顿、偶发 OOM,且弱网环境下白屏时间长,解决方案如下(可落地,贴合大厂要求):
- 卡顿问题解决:
- 滑动时暂停请求 :在 RecyclerView 滑动监听中,滑动状态为
SCROLL_STATE_SCROLLING时,调用pauseRequests(),停止滑动时resumeRequests(); - 限制图片尺寸 :所有列表图片,后台返回适配尺寸(如 400x400),客户端用
override(400, 400)强制限制,减少解码耗时; - 关闭过渡动画、去掉占位图,避免滑动时动画卡顿
- OOM 问题解决:
- 开启 RGB_565 配置,减少 Bitmap 内存占用;
- 检查自定义 Transformation ,确保复用 BitmapPool,避免手动创建 Bitmap;
- 调整内存缓存大小,根据设备内存动态设置(如低内存机型减小缓存);
- 弱网白屏问题解决:
- 预加载:列表预加载下一页图片,用户滑动时无需等待;
- 缩略图 :弱网环境下,用
thumbnail(0.3f)加载低清缩略图,再加载原图; - 缓存策略:磁盘缓存用 ALL,确保首次加载后,后续即使弱网也能从磁盘读取;
- 后续优化:接入图片加载监控,统计加载成功率、卡顿率,针对异常机型(如低内存机型)做单独适配。