rokevin
移动
前端
语言
  • 基础

    • Linux
    • 实施
    • 版本构建
  • 应用

    • WEB服务器
    • 数据库
  • 资讯

    • 工具
    • 部署
开放平台
产品设计
  • 人工智能
  • 云计算
计算机
其它
GitHub
移动
前端
语言
  • 基础

    • Linux
    • 实施
    • 版本构建
  • 应用

    • WEB服务器
    • 数据库
  • 资讯

    • 工具
    • 部署
开放平台
产品设计
  • 人工智能
  • 云计算
计算机
其它
GitHub
  • Glide

  • 一、 Glide 核心设计目标
  • 二、 Glide 整体工作流程(核心骨架)
    • 关键前置:Glide 初始化
  • 三、 核心原理 1:生命周期绑定(避免内存泄漏 & 无用请求)
    • 实现细节
  • 四、 核心原理 2:三级缓存机制(提升加载速度,减少资源消耗)
    • 一级缓存:内存缓存(LruCache + 弱引用)
    • 二级缓存:磁盘缓存(DiskLruCache)
    • 三级缓存:网络请求(/ 本地资源解码)
    • 三级缓存的完整查询流程
  • 五、 核心原理 3:图片解码与 Bitmap 优化(避免 OOM,提升性能)
  • 六、 核心原理 4:分线程任务调度(避免主线程卡顿)
  • 七、 核心原理 5:资源自动回收(减少内存占用)
  • 八、 Glide 核心流程总结(精简版)
  • 九、源码深度分析(Android,基于 Glide 4.x 版本)
    • 先明确 Glide 源码核心架构
    • 第一步:Glide 初始化流程(单例创建 + 全局配置)
      • 1. 核心入口:Glide.with() 触发初始化
      • 2. GlideBuilder:构建 Glide 核心组件
      • 3. 初始化关键结论
    • 第二步:请求构建流程(with() → load() → into())
      • 1. with():获取 RequestManager(生命周期绑定核心)
      • 关键细节:隐藏 RequestManagerFragment
      • 2. load():配置图片资源,构建 RequestBuilder
      • 关键细节
      • 3. into():触发请求执行(核心入口)
    • 第三步:引擎核心流程(Engine 协调三级缓存与任务调度)
      • 1. 核心入口:Engine.load()(三级缓存查询 + 任务分发)
      • 2. 内存缓存查询:loadFromMemoryCache()(强引用 → 弱引用)
      • 3. 解码任务:DecodeJob(磁盘缓存 → 网络请求 → 解码)
      • 4. 任务调度:线程池分工
    • 第四步:图片显示与资源回收
      • 1. 图片显示:ViewTarget.onResourceReady()
      • 2. 资源回收:生命周期触发 + 引用计数
    • Glide 源码核心设计亮点总结
  • 十、关键补充
  • 十一、 关键总结
  • 资料

Glide

GitHub | 官方文档 | Javadocs

Glide 是 Google 官方推荐的 Android 图片加载框架,其核心优势在于自动适配生命周期、高效优化内存、支持多类型资源加载,底层围绕「生命周期绑定 + 三级缓存 + 分阶段加载 + 自动内存优化」四大核心设计展开,以下是全面拆解的原理细节。

一、 Glide 核心设计目标

在理解原理前,先明确 Glide 的核心定位:以最低的内存开销、最流畅的用户体验,实现图片的高效加载、缓存与显示,解决手动操作 Bitmap 带来的 OOM、卡顿、内存泄漏等问题。

二、 Glide 整体工作流程(核心骨架)

Glide 的图片加载流程是一个分阶段、流水线式的处理过程,从发起请求到图片显示,整体分为 5 个核心阶段,且全程支持生命周期感知:

plaintext

发起加载请求(with() + load() + into())→ 三级缓存查询(内存→磁盘→网络)→ 图片解码与转换(Bitmap 优化)→ 图片显示 → 资源回收(生命周期触发)

关键前置:Glide 初始化

Glide 采用单例模式(默认),首次使用时会自动初始化,核心完成:

  1. 创建 GlideContext(封装应用上下文、配置信息)。
  2. 初始化缓存体系(内存缓存、磁盘缓存)。
  3. 初始化线程池(网络请求线程、解码线程,区分轻重任务)。
  4. 注册内置解码器(支持 JPG、PNG、GIF、Video 帧等)。

三、 核心原理 1:生命周期绑定(避免内存泄漏 & 无用请求)

这是 Glide 区别于其他图片加载框架的核心亮点之一,Glide 能自动感知 Activity/Fragment/View 的生命周期,从而暂停、恢复或取消图片加载请求,避免内存泄漏和无用请求消耗资源。

实现细节

  1. with() 方法的核心作用:

    • with() 支持传入 Context(Activity/Fragment/ApplicationContext),其核心是获取或创建一个与宿主生命周期绑定的「隐藏 Fragment」(无 UI 布局)。
    • 若传入 Activity/Fragment:Glide 会在当前 Activity/Fragment 中添加一个隐藏的 SupportRequestManagerFragment(AndroidX 版本),该 Fragment 与宿主生命周期同步。
    • 若传入 ApplicationContext:则绑定应用生命周期,只有应用退出时才会取消请求。
  2. 生命周期感知与请求管理:

    • 隐藏 Fragment 会监听 onStart()、onStop()、onDestroy() 等生命周期方法。
    • onStop():暂停所有正在进行的图片加载请求(尤其是网络请求),避免后台进程消耗流量和内存。
    • onStart():恢复暂停的请求,继续加载图片。
    • onDestroy():取消所有未完成的请求,释放相关资源(如 Bitmap 引用、线程资源),从根源避免内存泄漏。
  3. 请求管理核心类:RequestManager,负责管理与当前生命周期绑定的所有图片加载请求,协调请求的暂停、恢复、取消。

四、 核心原理 2:三级缓存机制(提升加载速度,减少资源消耗)

Glide 设计了 「内存缓存 → 磁盘缓存 → 网络请求」 的三级缓存体系,优先级从高到低,核心目标是「尽可能避免重复网络请求和重复解码 Bitmap」,提升图片加载速度,降低资源消耗。

一级缓存:内存缓存(LruCache + 弱引用)

内存缓存是最快的缓存(直接操作内存),Glide 采用「LruCache(强引用缓存) + WeakReference(弱引用缓存)」的双层内存缓存设计,对应 Glide 中的 MemoryCache 接口(默认实现 LruResourceCache)。

  1. 强引用缓存(LruCache):

    • 采用「最近最少使用(LRU)」策略,缓存最近使用过的 Bitmap 资源,当缓存大小超过设定阈值(默认是应用最大可用内存的 1/8)时,自动移除最久未使用的资源。
    • 核心作用:缓存常用图片,快速响应重复请求,避免重复解码。
    • 注意:Glide 加载图片时,先查询强引用缓存,若命中则直接返回,无需后续操作。
  2. 弱引用缓存(WeakReference):

    • 用于缓存那些从强引用缓存中被移除的资源,由 GC 自动回收(当内存不足时,GC 会优先回收弱引用资源)。
    • 核心作用:作为强引用缓存的补充,避免刚被移除的资源立即被回收,提升短时间内重复请求的命中率。
  3. 内存缓存的特殊逻辑:

    • Glide 默认会对「已显示到 ImageView 上的图片」从内存缓存中移除(放入弱引用缓存),避免内存缓存被大量已显示图片占用,保证新请求的缓存空间。
    • 可通过 skipMemoryCache(true) 跳过内存缓存。

二级缓存:磁盘缓存(DiskLruCache)

当内存缓存未命中时,Glide 会查询磁盘缓存,磁盘缓存对应 DiskCache 接口(默认实现 DiskLruCache),存储在设备的内部存储(默认)或外部存储中,缓存的是「解码前的原始数据」或「解码后的处理数据」。

  1. 磁盘缓存的两种类型(核心配置):

    Glide 通过 diskCacheStrategy() 配置磁盘缓存策略,核心分为两种缓存数据:

    • 原始数据缓存(Source):缓存从网络 / 本地获取的原始图片数据(如 JPG 原始字节流),不包含任何裁剪、缩放等处理。
    • 处理后数据缓存(Result):缓存经过解码、裁剪、缩放、转换后的最终 Bitmap 数据(与 ImageView 尺寸匹配)。
  2. 常用磁盘缓存策略:

    策略说明适用场景
    DiskCacheStrategy.ALL缓存原始数据 + 处理后数据常用场景,兼顾缓存命中率和灵活性
    DiskCacheStrategy.RESULT仅缓存处理后数据(默认策略)图片需裁剪 / 缩放适配 ImageView
    DiskCacheStrategy.SOURCE仅缓存原始数据需多次对图片进行不同处理(如不同尺寸显示)
    DiskCacheStrategy.NONE不缓存任何数据实时更新的图片(如验证码、实时榜单)
  3. 磁盘缓存的优势与注意事项:

    • 优势:缓存持久化,应用重启后仍有效,避免重复网络请求。
    • 注意:磁盘读写耗时,Glide 会在子线程中执行磁盘缓存的查询与写入,避免阻塞主线程。

三级缓存:网络请求(/ 本地资源解码)

当内存缓存和磁盘缓存均未命中时,Glide 才会发起网络请求(或从本地文件 / 资源中读取原始数据),获取图片的原始字节流。

  1. 网络请求核心:Glide 内置了 HttpUrlConnection,同时支持适配 OkHttp(需引入额外依赖),负责从网络获取图片数据。
  2. 数据回调:网络请求完成后,获取原始字节流,后续进入「图片解码与转换」阶段。

三级缓存的完整查询流程

plaintext

发起图片加载请求 → 
1. 查询「内存强引用缓存」→ 命中 → 直接显示图片 → 流程结束;
2. 内存强引用缓存未命中 → 查询「内存弱引用缓存」→ 命中 → 显示图片 + 放入强引用缓存 → 流程结束;
3. 内存缓存未命中 → 子线程查询「磁盘缓存」→ 命中 → 读取缓存数据 → 解码转换 → 显示图片 + 放入内存缓存 → 流程结束;
4. 磁盘缓存未命中 → 发起网络请求 → 获取原始数据 → 写入磁盘缓存 → 解码转换 → 显示图片 + 放入内存缓存 → 流程结束。

五、 核心原理 3:图片解码与 Bitmap 优化(避免 OOM,提升性能)

Glide 对 Bitmap 的解码和内存优化做了大量底层封装,这是其避免 OOM 的核心保障,相比手动操作 Bitmap 更高效、更安全。

  1. 自动适配 ImageView 尺寸,按需解码:

    • Glide 会自动获取 ImageView 的宽高(通过 into(imageView)),然后根据 ImageView 的尺寸计算最优的「采样率(inSampleSize)」,避免解码高分辨率图片为超大 Bitmap。
    • 核心:不会解码超出 ImageView 显示需求的 Bitmap,从根源减少内存占用(例如,一张 2000×2000 的图片,适配 400×400 的 ImageView,Glide 会自动缩放采样,避免加载 2000×2000 的完整 Bitmap)。
  2. 灵活的 Bitmap 像素配置:

    • Glide 会根据图片类型(是否有透明通道)自动选择最优的

      Bitmap.Config
      

      :

      • 有透明通道(如 PNG):使用 ARGB_8888(32 位真彩色)。
      • 无透明通道(如 JPG):自动降级为 RGB_565(16 位彩色),减少 50% 内存占用。
    • 可通过 encodeFormat() 手动配置像素格式。

  3. 分阶段解码与渐进式加载:

    • 分阶段解码:将大图片的解码过程分为多个小阶段,每阶段解码一部分数据,避免单次解码占用过多内存。
    • 渐进式加载:支持 JPG 图片的渐进式加载(类似网页图片的模糊→清晰),先加载低分辨率缩略图,再逐步加载高清数据,提升用户体验。
  4. 解码器注册机制:

    • Glide 采用「解码器注册」模式,支持多种资源类型的解码(JPG、PNG、GIF、WebP、Video 帧等)。
    • 核心解码器:BitmapDecoder(解码静态图片)、GifDecoder(解码 GIF 动图),可自定义解码器扩展支持的图片格式。

六、 核心原理 4:分线程任务调度(避免主线程卡顿)

Glide 的所有耗时操作(磁盘读写、网络请求、图片解码)均在子线程中执行,主线程仅负责最终的图片显示,避免阻塞主线程导致 UI 卡顿。

  1. 线程池设计:Glide 内置了两个核心线程池,区分不同类型的任务,提升调度效率:

    • 磁盘缓存线程池:用于执行磁盘缓存的查询与写入,核心线程数固定(默认 1),因为磁盘 I/O 是串行操作,多线程不会提升效率,反而会增加磁盘开销。
    • 网络请求 / 解码线程池:用于执行网络请求、图片解码、转换等任务,核心线程数可配置(默认根据设备 CPU 核心数动态调整),支持并行执行,提升多图片加载效率。
  2. 任务调度核心类:Engine,负责协调缓存查询、任务分发、线程调度,避免重复请求(例如,多个 ImageView 同时加载同一张图片,Glide 会只发起一次请求,结果共享)。

  3. 主线程回调:图片解码与转换完成后,通过 Handler 将结果回调到主线程,更新 ImageView 显示图片,保证 UI 操作的线程安全性。

七、 核心原理 5:资源自动回收(减少内存占用)

Glide 会自动管理 Bitmap 资源的回收,避免内存泄漏和 OOM,核心实现:

  1. 生命周期触发回收:当宿主 Activity/Fragment 销毁时,RequestManager 会取消所有未完成的请求,释放 Bitmap 引用,触发 recycle() 释放 Native 内存。

  2. 弱引用自动回收:已显示的图片会被放入弱引用缓存,当内存不足时,GC 会自动回收这些资源。

  3. Bitmap 池(BitmapPool)

    :Glide 引入了

    BitmapPool
    

    (基于 LRU 策略),用于复用 Bitmap 实例,避免频繁创建和销毁 Bitmap 带来的内存开销和 GC 压力。

    • 核心:当 Bitmap 不再需要时,不会直接回收,而是放入 BitmapPool 中,后续需要创建 Bitmap 时,优先从池中复用,减少内存分配和 GC 触发。

八、 Glide 核心流程总结(精简版)

  1. 绑定生命周期:with() 方法创建隐藏 Fragment,绑定宿主生命周期,获取 RequestManager。
  2. 构建请求:load() 指定图片资源,配置缓存策略、解码参数等。
  3. 发起请求:into() 触发请求,先查询三级缓存。
  4. 任务调度:缓存未命中则分发到子线程,执行网络请求 / 解码。
  5. 图片显示:解码完成后,主线程回调更新 ImageView。
  6. 资源回收:生命周期触发时,取消请求,回收 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. 初始化关键结论

  1. Glide 仅初始化一次,单例持有全局核心组件(缓存、线程池、引擎等)。
  2. GlideContext 是 Glide 的「上下文容器」,隔离应用 Context,避免内存泄漏。
  3. 所有缓存和线程池均采用 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

  1. RequestManagerFragment 是一个无 UI 的隐藏 Fragment,其生命周期与宿主 Activity/Fragment 完全同步。
  2. 该 Fragment 持有 ActivityFragmentLifecycle(生命周期分发器),会将自身的 onStart()/onStop()/onDestroy() 分发给 RequestManager。
  3. 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;
}
关键细节
  1. ViewTarget:封装 ImageView,负责「接收解码结果 + 更新 UI 显示 + 监听 View 生命周期」。
  2. buildRequest():构建完整的 Request 对象,包含所有请求配置和回调。
  3. 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);
  }
}
关键子流程
  1. loadFromDiskCache():查询磁盘缓存(DiskLruCache),读取缓存的原始数据或处理后数据,无需网络请求。
  2. loadFromSource():发起网络请求(或读取本地资源),获取原始字节流,同时将原始数据写入磁盘缓存。
  3. decode():核心解码方法,根据图片类型(JPG/PNG/GIF)选择对应的解码器(BitmapDecoder/GifDecoder),将字节流解码为 EngineResource(封装 Bitmap/GIF 等资源)。
  4. 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 的资源回收是「自动触发」的,核心实现有两点:

  1. 生命周期触发回收:当宿主 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();
      }
    }
    
  2. 引用计数回收: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 源码核心设计亮点总结

  1. 生命周期绑定:通过隐藏 Fragment 感知宿主生命周期,从根源避免内存泄漏,无需开发者手动管理。
  2. 三级缓存 + 引用计数:LruCache 强引用 + 弱引用 + DiskLruCache,兼顾加载速度和内存安全,引用计数避免资源误回收。
  3. 重复请求去重:通过 Engine 的 jobs 缓存正在进行的请求,避免多个 ImageView 加载同一张图片时发起重复请求。
  4. Bitmap 复用池:减少 Bitmap 的创建与销毁,降低 GC 压力,避免 OOM。
  5. 接口解耦 + 可扩展:所有核心模块(缓存、解码器、线程池)均提供接口,支持自定义实现(如自定义磁盘缓存、解码器)。
  6. 主线程安全:耗时操作均在子线程执行,主线程仅负责 UI 显示,避免卡顿。

十、关键补充

  • Glide 4.x 相比 3.x 的核心变化:引入 AppGlideModule 支持自定义全局配置,替代 3.x 的 GlideModule,更符合 AndroidX 规范。
  • 若需深入学习,建议优先阅读 Engine、DecodeJob、RequestManager 三个核心类的源码,它们是 Glide 的核心骨架。

十一、 关键总结

Glide 的核心原理可概括为「一个核心,五大支撑」:

  1. 核心目标:高效、安全地加载图片,避免 OOM 和卡顿。
  2. 五大支撑:生命周期绑定(防泄漏)、三级缓存(提速度)、智能解码(优内存)、分线程调度(保流畅)、自动回收(减开销)。
  3. 核心优势:无需开发者手动处理 Bitmap 优化和生命周期管理,开箱即用,适配各种场景。

资料

Android高工面试:用Glide加载Gif导致的卡顿,说一下你的优化思路
Glide定制--使用Okhttp3替换默认HttpURLConnection,实现添加请求头等需求
Android图片缓存之Glide进阶
Glide-note
Glide 源码分析解读-缓存模块-基于最新版Glide 4.9.0
Glide 源码分析解读-基于最新版Glide 4.9.0

最近更新:: 2026/1/15 03:00
Contributors: luokaiwen, 罗凯文