Glide
Glide 是 Google 官方推荐的 Android 图片加载框架,其核心优势在于自动适配生命周期、高效优化内存、支持多类型资源加载,底层围绕「生命周期绑定 + 三级缓存 + 分阶段加载 + 自动内存优化」四大核心设计展开,以下是全面拆解的原理细节。
一、 Glide 核心设计目标
在理解原理前,先明确 Glide 的核心定位:以最低的内存开销、最流畅的用户体验,实现图片的高效加载、缓存与显示,解决手动操作 Bitmap 带来的 OOM、卡顿、内存泄漏等问题。
二、 Glide 整体工作流程(核心骨架)
Glide 的图片加载流程是一个分阶段、流水线式的处理过程,从发起请求到图片显示,整体分为 5 个核心阶段,且全程支持生命周期感知:
plaintext
发起加载请求(with() + load() + into())→ 三级缓存查询(内存→磁盘→网络)→ 图片解码与转换(Bitmap 优化)→ 图片显示 → 资源回收(生命周期触发)
关键前置:Glide 初始化
Glide 采用单例模式(默认),首次使用时会自动初始化,核心完成:
- 创建
GlideContext(封装应用上下文、配置信息)。 - 初始化缓存体系(内存缓存、磁盘缓存)。
- 初始化线程池(网络请求线程、解码线程,区分轻重任务)。
- 注册内置解码器(支持 JPG、PNG、GIF、Video 帧等)。
三、 核心原理 1:生命周期绑定(避免内存泄漏 & 无用请求)
这是 Glide 区别于其他图片加载框架的核心亮点之一,Glide 能自动感知 Activity/Fragment/View 的生命周期,从而暂停、恢复或取消图片加载请求,避免内存泄漏和无用请求消耗资源。
实现细节
with()方法的核心作用:with()支持传入Context(Activity/Fragment/ApplicationContext),其核心是获取或创建一个与宿主生命周期绑定的「隐藏 Fragment」(无 UI 布局)。- 若传入
Activity/Fragment:Glide 会在当前Activity/Fragment中添加一个隐藏的SupportRequestManagerFragment(AndroidX 版本),该 Fragment 与宿主生命周期同步。 - 若传入
ApplicationContext:则绑定应用生命周期,只有应用退出时才会取消请求。
生命周期感知与请求管理:
- 隐藏 Fragment 会监听
onStart()、onStop()、onDestroy()等生命周期方法。 onStop():暂停所有正在进行的图片加载请求(尤其是网络请求),避免后台进程消耗流量和内存。onStart():恢复暂停的请求,继续加载图片。onDestroy():取消所有未完成的请求,释放相关资源(如 Bitmap 引用、线程资源),从根源避免内存泄漏。
- 隐藏 Fragment 会监听
请求管理核心类:
RequestManager,负责管理与当前生命周期绑定的所有图片加载请求,协调请求的暂停、恢复、取消。
四、 核心原理 2:三级缓存机制(提升加载速度,减少资源消耗)
Glide 设计了 「内存缓存 → 磁盘缓存 → 网络请求」 的三级缓存体系,优先级从高到低,核心目标是「尽可能避免重复网络请求和重复解码 Bitmap」,提升图片加载速度,降低资源消耗。
一级缓存:内存缓存(LruCache + 弱引用)
内存缓存是最快的缓存(直接操作内存),Glide 采用「LruCache(强引用缓存) + WeakReference(弱引用缓存)」的双层内存缓存设计,对应 Glide 中的 MemoryCache 接口(默认实现 LruResourceCache)。
强引用缓存(LruCache):
- 采用「最近最少使用(LRU)」策略,缓存最近使用过的 Bitmap 资源,当缓存大小超过设定阈值(默认是应用最大可用内存的 1/8)时,自动移除最久未使用的资源。
- 核心作用:缓存常用图片,快速响应重复请求,避免重复解码。
- 注意:Glide 加载图片时,先查询强引用缓存,若命中则直接返回,无需后续操作。
弱引用缓存(WeakReference):
- 用于缓存那些从强引用缓存中被移除的资源,由 GC 自动回收(当内存不足时,GC 会优先回收弱引用资源)。
- 核心作用:作为强引用缓存的补充,避免刚被移除的资源立即被回收,提升短时间内重复请求的命中率。
内存缓存的特殊逻辑:
- Glide 默认会对「已显示到 ImageView 上的图片」从内存缓存中移除(放入弱引用缓存),避免内存缓存被大量已显示图片占用,保证新请求的缓存空间。
- 可通过
skipMemoryCache(true)跳过内存缓存。
二级缓存:磁盘缓存(DiskLruCache)
当内存缓存未命中时,Glide 会查询磁盘缓存,磁盘缓存对应 DiskCache 接口(默认实现 DiskLruCache),存储在设备的内部存储(默认)或外部存储中,缓存的是「解码前的原始数据」或「解码后的处理数据」。
磁盘缓存的两种类型(核心配置):
Glide 通过
diskCacheStrategy()配置磁盘缓存策略,核心分为两种缓存数据:- 原始数据缓存(Source):缓存从网络 / 本地获取的原始图片数据(如 JPG 原始字节流),不包含任何裁剪、缩放等处理。
- 处理后数据缓存(Result):缓存经过解码、裁剪、缩放、转换后的最终 Bitmap 数据(与 ImageView 尺寸匹配)。
常用磁盘缓存策略:
策略 说明 适用场景 DiskCacheStrategy.ALL缓存原始数据 + 处理后数据 常用场景,兼顾缓存命中率和灵活性 DiskCacheStrategy.RESULT仅缓存处理后数据(默认策略) 图片需裁剪 / 缩放适配 ImageView DiskCacheStrategy.SOURCE仅缓存原始数据 需多次对图片进行不同处理(如不同尺寸显示) DiskCacheStrategy.NONE不缓存任何数据 实时更新的图片(如验证码、实时榜单) 磁盘缓存的优势与注意事项:
- 优势:缓存持久化,应用重启后仍有效,避免重复网络请求。
- 注意:磁盘读写耗时,Glide 会在子线程中执行磁盘缓存的查询与写入,避免阻塞主线程。
三级缓存:网络请求(/ 本地资源解码)
当内存缓存和磁盘缓存均未命中时,Glide 才会发起网络请求(或从本地文件 / 资源中读取原始数据),获取图片的原始字节流。
- 网络请求核心:Glide 内置了
HttpUrlConnection,同时支持适配 OkHttp(需引入额外依赖),负责从网络获取图片数据。 - 数据回调:网络请求完成后,获取原始字节流,后续进入「图片解码与转换」阶段。
三级缓存的完整查询流程
plaintext
发起图片加载请求 →
1. 查询「内存强引用缓存」→ 命中 → 直接显示图片 → 流程结束;
2. 内存强引用缓存未命中 → 查询「内存弱引用缓存」→ 命中 → 显示图片 + 放入强引用缓存 → 流程结束;
3. 内存缓存未命中 → 子线程查询「磁盘缓存」→ 命中 → 读取缓存数据 → 解码转换 → 显示图片 + 放入内存缓存 → 流程结束;
4. 磁盘缓存未命中 → 发起网络请求 → 获取原始数据 → 写入磁盘缓存 → 解码转换 → 显示图片 + 放入内存缓存 → 流程结束。
五、 核心原理 3:图片解码与 Bitmap 优化(避免 OOM,提升性能)
Glide 对 Bitmap 的解码和内存优化做了大量底层封装,这是其避免 OOM 的核心保障,相比手动操作 Bitmap 更高效、更安全。
自动适配 ImageView 尺寸,按需解码:
- Glide 会自动获取
ImageView的宽高(通过into(imageView)),然后根据 ImageView 的尺寸计算最优的「采样率(inSampleSize)」,避免解码高分辨率图片为超大 Bitmap。 - 核心:不会解码超出 ImageView 显示需求的 Bitmap,从根源减少内存占用(例如,一张 2000×2000 的图片,适配 400×400 的 ImageView,Glide 会自动缩放采样,避免加载 2000×2000 的完整 Bitmap)。
- Glide 会自动获取
灵活的 Bitmap 像素配置:
Glide 会根据图片类型(是否有透明通道)自动选择最优的
Bitmap.Config:
- 有透明通道(如 PNG):使用
ARGB_8888(32 位真彩色)。 - 无透明通道(如 JPG):自动降级为
RGB_565(16 位彩色),减少 50% 内存占用。
- 有透明通道(如 PNG):使用
可通过
encodeFormat()手动配置像素格式。
分阶段解码与渐进式加载:
- 分阶段解码:将大图片的解码过程分为多个小阶段,每阶段解码一部分数据,避免单次解码占用过多内存。
- 渐进式加载:支持 JPG 图片的渐进式加载(类似网页图片的模糊→清晰),先加载低分辨率缩略图,再逐步加载高清数据,提升用户体验。
解码器注册机制:
- Glide 采用「解码器注册」模式,支持多种资源类型的解码(JPG、PNG、GIF、WebP、Video 帧等)。
- 核心解码器:
BitmapDecoder(解码静态图片)、GifDecoder(解码 GIF 动图),可自定义解码器扩展支持的图片格式。
六、 核心原理 4:分线程任务调度(避免主线程卡顿)
Glide 的所有耗时操作(磁盘读写、网络请求、图片解码)均在子线程中执行,主线程仅负责最终的图片显示,避免阻塞主线程导致 UI 卡顿。
线程池设计:Glide 内置了两个核心线程池,区分不同类型的任务,提升调度效率:
- 磁盘缓存线程池:用于执行磁盘缓存的查询与写入,核心线程数固定(默认 1),因为磁盘 I/O 是串行操作,多线程不会提升效率,反而会增加磁盘开销。
- 网络请求 / 解码线程池:用于执行网络请求、图片解码、转换等任务,核心线程数可配置(默认根据设备 CPU 核心数动态调整),支持并行执行,提升多图片加载效率。
任务调度核心类:
Engine,负责协调缓存查询、任务分发、线程调度,避免重复请求(例如,多个 ImageView 同时加载同一张图片,Glide 会只发起一次请求,结果共享)。主线程回调:图片解码与转换完成后,通过
Handler将结果回调到主线程,更新ImageView显示图片,保证 UI 操作的线程安全性。
七、 核心原理 5:资源自动回收(减少内存占用)
Glide 会自动管理 Bitmap 资源的回收,避免内存泄漏和 OOM,核心实现:
生命周期触发回收:当宿主
Activity/Fragment销毁时,RequestManager会取消所有未完成的请求,释放 Bitmap 引用,触发recycle()释放 Native 内存。弱引用自动回收:已显示的图片会被放入弱引用缓存,当内存不足时,GC 会自动回收这些资源。
Bitmap 池(
BitmapPool):Glide 引入了
BitmapPool(基于 LRU 策略),用于复用 Bitmap 实例,避免频繁创建和销毁 Bitmap 带来的内存开销和 GC 压力。
- 核心:当 Bitmap 不再需要时,不会直接回收,而是放入
BitmapPool中,后续需要创建 Bitmap 时,优先从池中复用,减少内存分配和 GC 触发。
- 核心:当 Bitmap 不再需要时,不会直接回收,而是放入
八、 Glide 核心流程总结(精简版)
- 绑定生命周期:
with()方法创建隐藏 Fragment,绑定宿主生命周期,获取RequestManager。 - 构建请求:
load()指定图片资源,配置缓存策略、解码参数等。 - 发起请求:
into()触发请求,先查询三级缓存。 - 任务调度:缓存未命中则分发到子线程,执行网络请求 / 解码。
- 图片显示:解码完成后,主线程回调更新 ImageView。
- 资源回收:生命周期触发时,取消请求,回收 Bitmap 资源。
九、源码深度分析(Android,基于 Glide 4.x 版本)
Glide 作为 Google 官方推荐的图片加载框架,其源码设计体现了「高内聚、低耦合、可扩展、性能优先」的核心思想,整体采用「建造者模式 + 责任链模式 + 线程池调度」,核心围绕「请求构建、生命周期绑定、三级缓存、解码显示、资源回收」五大核心流程展开。以下是从源码层面的逐环节拆解。
先明确 Glide 源码核心架构
Glide 源码整体分为 5 大核心模块,各模块职责清晰,通过接口解耦,便于扩展和维护:
| 核心模块 | 核心类 / 接口 | 核心职责 |
|---|---|---|
| 初始化模块 | Glide、GlideBuilder、GlideContext | 单例初始化、全局配置(缓存大小、线程池、解码器等) |
| 请求构建模块 | RequestManager、RequestBuilder、DrawableTypeRequest | 构建图片加载请求(资源地址、缓存策略、图片配置等) |
| 生命周期绑定模块 | RequestManagerFragment(隐藏 Fragment)、ActivityFragmentLifecycle | 感知宿主生命周期,管理请求的暂停 / 恢复 / 取消 |
| 引擎核心模块(核心) | Engine、EngineJob、DecodeJob | 协调三级缓存、任务调度、重复请求去重 |
| 缓存模块 | MemoryCache(LruResourceCache)、DiskCache(DiskLruCache)、BitmapPool | 实现内存缓存、磁盘缓存、Bitmap 复用池 |
| 解码模块 | ResourceDecoder、BitmapDecoder、GifDecoder | 图片解码(原始数据 → Bitmap/GIF 等资源) |
第一步:Glide 初始化流程(单例创建 + 全局配置)
Glide 采用 单例模式 初始化,首次调用 Glide.with() 时会触发初始化,核心入口在 Glide 类的静态方法中。
1. 核心入口:Glide.with() 触发初始化
// Glide 类的静态 with() 方法(简化版)
public static RequestManager with(Context context) {
// 1. 获取 Glide 单例实例(触发初始化)
Glide glide = Glide.get(context);
// 2. 获取 RequestManager(生命周期绑定核心)
return glide.getRequestManagerRetriever().get(context);
}
// Glide.get() 单例创建逻辑
public static Glide get(Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
// 3. 构建 Glide 实例(核心:GlideBuilder)
Context applicationContext = context.getApplicationContext();
GlideBuilder builder = new GlideBuilder();
// 4. 应用默认配置 + 自定义配置
builder = applyDefaultConfiguration(applicationContext, builder);
// 5. 创建 Glide 单例
glide = builder.build(applicationContext);
}
}
}
return glide;
}
2. GlideBuilder:构建 Glide 核心组件
GlideBuilder 是 Glide 的「构建者」,负责创建全局核心组件,核心方法 build() 如下(简化版):
public Glide build(Context context) {
// 1. 创建 GlideContext(封装上下文 + 全局配置)
GlideContext glideContext = new GlideContext(context, ...);
// 2. 初始化内存缓存(默认:LruResourceCache,大小为应用最大内存的 1/8)
MemoryCache memoryCache = new LruResourceCache(calculateMemoryCacheSize(context));
// 3. 初始化 Bitmap 复用池(默认:LruBitmapPool,复用 Bitmap 减少 GC)
BitmapPool bitmapPool = new LruBitmapPool(calculateBitmapPoolSize(context));
// 4. 初始化磁盘缓存(默认:DiskLruCache,存储在内部存储,大小 250MB)
DiskCache diskCache = new DiskLruCacheFactory(...).build();
// 5. 初始化线程池(磁盘线程池 + 网络/解码线程池)
ExecutorService diskExecutor = Executors.newSingleThreadExecutor(); // 磁盘 I/O 串行
ExecutorService networkExecutor = new ThreadPoolExecutor(...); // 网络/解码并行
// 6. 初始化核心引擎(Engine)
Engine engine = new Engine(memoryCache, bitmapPool, diskCache, diskExecutor, networkExecutor);
// 7. 返回 Glide 实例,持有所有核心组件引用
return new Glide(glideContext, engine, ...);
}
3. 初始化关键结论
- Glide 仅初始化一次,单例持有全局核心组件(缓存、线程池、引擎等)。
GlideContext是 Glide 的「上下文容器」,隔离应用Context,避免内存泄漏。- 所有缓存和线程池均采用 LRU 策略,优先复用资源,减少 GC 和资源消耗。
第二步:请求构建流程(with() → load() → into())
Glide 的请求构建采用 建造者模式,通过 with() → load() → into() 三步构建完整请求,每一步都返回对应的构建者,支持链式调用。
1. with():获取 RequestManager(生命周期绑定核心)
with() 方法的核心不是初始化 Glide,而是 获取与宿主生命周期绑定的 RequestManager,其核心实现在 RequestManagerRetriever 类中:
// RequestManagerRetriever.get() 方法(简化版)
public RequestManager get(Context context) {
if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof Fragment) {
return get((Fragment) context);
}
// 应用上下文:绑定应用生命周期,仅应用退出时取消请求
return getApplicationManager(context);
}
// 针对 Activity 的处理(核心:添加隐藏 Fragment)
public RequestManager get(Activity activity) {
// 1. 检查是否是主线程(Glide 要求主线程发起请求)
checkMainThread();
// 2. 获取 Activity 的 FragmentManager
FragmentManager fragmentManager = activity.getSupportFragmentManager();
// 3. 获取或创建隐藏 Fragment(RequestManagerFragment)
RequestManagerFragment fragment = getRequestManagerFragment(fragmentManager);
// 4. 获取 RequestManager(与隐藏 Fragment 绑定)
RequestManager requestManager = fragment.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(glide, fragment.getLifecycle());
fragment.setRequestManager(requestManager);
}
return requestManager;
}
关键细节:隐藏 RequestManagerFragment
RequestManagerFragment是一个无 UI 的隐藏 Fragment,其生命周期与宿主Activity/Fragment完全同步。- 该 Fragment 持有
ActivityFragmentLifecycle(生命周期分发器),会将自身的onStart()/onStop()/onDestroy()分发给RequestManager。 RequestManager监听生命周期事件,从而暂停 / 恢复 / 取消请求,避免内存泄漏。
2. load():配置图片资源,构建 RequestBuilder
RequestManager.load() 方法负责指定图片资源(网络 URL、本地文件、资源 ID 等),并返回 RequestBuilder(请求构建者),简化版源码:
// RequestManager.load() 方法
public RequestBuilder<Drawable> load(String url) {
// 1. 创建 RequestBuilder,绑定 RequestManager
RequestBuilder<Drawable> builder = new RequestBuilder<>(this, Drawable.class);
// 2. 配置图片资源
builder.load(url);
// 3. 返回 builder,支持链式配置(缓存策略、尺寸、占位图等)
return builder;
}
// RequestBuilder.load() 方法(存储资源信息)
public RequestBuilder<TranscodeType> load(String url) {
this.model = url; // 存储资源地址(model 是泛型,支持多种资源类型)
return this;
}
关键细节
RequestBuilder负责存储所有请求配置(缓存策略diskCacheStrategy()、图片尺寸override()、占位图placeholder()等)。- 支持泛型返回类型(
Drawable、Bitmap等),通过「转码器」实现资源类型转换。
3. into():触发请求执行(核心入口)
into() 是请求构建的最后一步,也是触发图片加载的核心入口,简化版源码如下(RequestBuilder.into()):
public ViewTarget<ImageView, TranscodeType> into(ImageView imageView) {
// 1. 检查参数合法性(ImageView 非空、主线程等)
checkNotNull(imageView);
checkMainThread();
// 2. 构建 ViewTarget(封装 ImageView,负责最终图片显示)
ViewTarget<ImageView, TranscodeType> target = new ImageViewTarget(imageView);
// 3. 配置请求(绑定 target、生命周期等)
Request request = buildRequest(target);
// 4. 提交请求(交给 RequestManager 管理)
requestManager.track(target, request);
return target;
}
关键细节
ViewTarget:封装ImageView,负责「接收解码结果 + 更新 UI 显示 + 监听 View 生命周期」。buildRequest():构建完整的Request对象,包含所有请求配置和回调。track():RequestManager跟踪该请求,将其加入请求队列,与生命周期绑定。
第三步:引擎核心流程(Engine 协调三级缓存与任务调度)
Engine 是 Glide 的「核心引擎」,负责协调三级缓存、任务调度、重复请求去重,是 Glide 源码的核心所在。请求提交后,最终会进入 Engine.load() 方法。
1. 核心入口:Engine.load()(三级缓存查询 + 任务分发)
// Engine.load() 方法(简化版)
public <R> LoadStatus load(...) {
// 1. 生成唯一缓存 Key(根据资源地址、尺寸、缓存策略等生成)
Key key = generateKey(model, width, height, ...);
// 2. 第一步:查询内存缓存(强引用 + 弱引用)
EngineResource<?> cachedResource = loadFromMemoryCache(key);
if (cachedResource != null) {
// 内存缓存命中:直接回调结果,显示图片
callback.onResourceReady(cachedResource, DataSource.MEMORY_CACHE);
return null;
}
// 3. 第二步:检查是否有正在进行的相同请求(去重)
EngineJob<?> currentJob = jobs.get(key, isMemoryCacheable);
if (currentJob != null) {
// 存在相同请求:加入回调队列,共享请求结果
currentJob.addCallback(callback);
return new LoadStatus(callback, currentJob);
}
// 4. 第三步:创建 EngineJob(任务封装)和 DecodeJob(解码任务)
EngineJob<R> engineJob = createEngineJob(...);
DecodeJob<R> decodeJob = createDecodeJob(...);
// 5. 存储正在进行的任务(用于去重)
jobs.put(key, engineJob);
// 6. 提交 DecodeJob 到线程池执行(磁盘查询 → 网络请求 → 解码)
engineJob.start(decodeJob);
// 7. 返回 LoadStatus(用于取消请求)
return new LoadStatus(callback, engineJob);
}
2. 内存缓存查询:loadFromMemoryCache()(强引用 → 弱引用)
private EngineResource<?> loadFromMemoryCache(Key key) {
// 第一步:查询强引用缓存(LruResourceCache)
EngineResource<?> resource = memoryCache.remove(key);
if (resource != null) {
// 强引用缓存命中:放入弱引用缓存 + 标记为「正在使用」
activeResources.put(key, new ResourceWeakReference(key, resource, ...));
return resource;
}
// 第二步:查询弱引用缓存(activeResources)
ResourceWeakReference weakRef = activeResources.get(key);
if (weakRef != null) {
EngineResource<?> weakResource = weakRef.get();
if (weakResource != null) {
weakResource.acquire(); // 增加引用计数,避免被回收
return weakResource;
}
// 弱引用已被 GC 回收:移除无效引用
activeResources.remove(key);
}
return null;
}
关键细节
memoryCache:强引用缓存(LruResourceCache),缓存最近使用的资源。activeResources:弱引用缓存,存储正在显示的图片资源,由 GC 自动回收。- 引用计数:
EngineResource采用引用计数机制,避免资源在使用过程中被回收。
3. 解码任务:DecodeJob(磁盘缓存 → 网络请求 → 解码)
DecodeJob 是 Glide 的「核心任务执行类」,运行在子线程,负责完成「磁盘缓存查询 → 网络请求 → 图片解码 → 缓存写入」的完整流程,核心方法 run() 如下(简化版):
@Override
public void run() {
try {
// 1. 初始化任务(检查配置、准备解码器)
init();
// 2. 第二步:查询磁盘缓存(内存缓存未命中)
Resource<R> resource = loadFromDiskCache();
if (resource == null) {
// 3. 第三步:网络请求/本地资源读取(磁盘缓存未命中)
resource = loadFromSource();
}
// 4. 解码完成:处理结果(写入缓存 + 回调主线程)
notifyEncodeAndRelease(resource);
} catch (Exception e) {
// 异常处理:回调错误信息
notifyFailed(e);
}
}
关键子流程
loadFromDiskCache():查询磁盘缓存(DiskLruCache),读取缓存的原始数据或处理后数据,无需网络请求。loadFromSource():发起网络请求(或读取本地资源),获取原始字节流,同时将原始数据写入磁盘缓存。decode():核心解码方法,根据图片类型(JPG/PNG/GIF)选择对应的解码器(BitmapDecoder/GifDecoder),将字节流解码为EngineResource(封装 Bitmap/GIF 等资源)。notifyEncodeAndRelease():将解码后的资源写入内存缓存,然后通过Handler回调到主线程,更新ImageView显示。
4. 任务调度:线程池分工
DecodeJob 提交后,由 Engine 分配到对应的线程池执行:
- 磁盘缓存查询 / 写入:分配到「磁盘线程池」(单线程),因为磁盘 I/O 是串行操作,多线程会降低效率。
- 网络请求 / 图片解码:分配到「网络 / 解码线程池」(多线程,根据 CPU 核心数动态调整),支持并行执行,提升多图片加载效率。
第四步:图片显示与资源回收
1. 图片显示:ViewTarget.onResourceReady()
解码完成后,Engine 通过 Handler 将结果回调到主线程,最终调用 ViewTarget.onResourceReady() 方法更新 ImageView:
// ImageViewTarget.onResourceReady() 方法
@Override
public void onResourceReady(Drawable resource, Transition<? super Drawable> transition) {
// 1. 应用过渡动画(如淡入淡出)
if (transition != null) {
transition.transition(resource, this);
} else {
// 2. 直接设置图片到 ImageView
setResource(resource);
}
}
// 最终设置图片
@Override
protected void setResource(Drawable resource) {
imageView.setImageDrawable(resource);
}
2. 资源回收:生命周期触发 + 引用计数
Glide 的资源回收是「自动触发」的,核心实现有两点:
生命周期触发回收:当宿主
Activity/Fragment销毁时,RequestManager会调用Request.clear(),取消请求并释放
EngineResource引用:// Request.clear() 方法 public void clear() { // 1. 取消任务(若未完成) if (engineJob != null) { engineJob.removeCallback(callback); engineJob.cancel(); } // 2. 释放资源引用(减少引用计数) if (resource != null) { resource.release(); } }引用计数回收:
EngineResource采用引用计数机制,当引用计数为 0 时,自动将资源放入内存缓存或 Bitmap 复用池:// EngineResource.release() 方法 public void release() { synchronized (this) { // 减少引用计数 if (--acquired == 0) { // 引用计数为 0:回收资源 if (isCacheable) { // 放入内存缓存 memoryCache.put(key, this); } else { // 放入 Bitmap 复用池(若为 Bitmap 资源) bitmapPool.put(bitmap); } } } }
Glide 源码核心设计亮点总结
- 生命周期绑定:通过隐藏 Fragment 感知宿主生命周期,从根源避免内存泄漏,无需开发者手动管理。
- 三级缓存 + 引用计数:LruCache 强引用 + 弱引用 + DiskLruCache,兼顾加载速度和内存安全,引用计数避免资源误回收。
- 重复请求去重:通过
Engine的jobs缓存正在进行的请求,避免多个 ImageView 加载同一张图片时发起重复请求。 - Bitmap 复用池:减少 Bitmap 的创建与销毁,降低 GC 压力,避免 OOM。
- 接口解耦 + 可扩展:所有核心模块(缓存、解码器、线程池)均提供接口,支持自定义实现(如自定义磁盘缓存、解码器)。
- 主线程安全:耗时操作均在子线程执行,主线程仅负责 UI 显示,避免卡顿。
十、关键补充
- Glide 4.x 相比 3.x 的核心变化:引入
AppGlideModule支持自定义全局配置,替代 3.x 的GlideModule,更符合 AndroidX 规范。 - 若需深入学习,建议优先阅读
Engine、DecodeJob、RequestManager三个核心类的源码,它们是 Glide 的核心骨架。
十一、 关键总结
Glide 的核心原理可概括为「一个核心,五大支撑」:
- 核心目标:高效、安全地加载图片,避免 OOM 和卡顿。
- 五大支撑:生命周期绑定(防泄漏)、三级缓存(提速度)、智能解码(优内存)、分线程调度(保流畅)、自动回收(减开销)。
- 核心优势:无需开发者手动处理 Bitmap 优化和生命周期管理,开箱即用,适配各种场景。
资料
Android高工面试:用Glide加载Gif导致的卡顿,说一下你的优化思路
Glide定制--使用Okhttp3替换默认HttpURLConnection,实现添加请求头等需求
Android图片缓存之Glide进阶
Glide-note
Glide 源码分析解读-缓存模块-基于最新版Glide 4.9.0
Glide 源码分析解读-基于最新版Glide 4.9.0