Glide源码解析

news2025/6/5 19:33:21

前言

Glide是一款专为Android设计的开源图片加载库。有以下特点:1.支持高效加载网络、本地及资源图片;2.具备良好的缓存策略及生命周期管理策略;3.提供了简易的API和强大的功能。本文将对其源码进行剖析。

基本使用

dependencies {
    compile 'com.github.bumptech.glide:glide:3.7.0'
}
<uses-permission android:name="android.permission.INTERNET" />
// 基础用法:加载网络图片
Glide.with(context)
    .load("https://ts1.tc.mm.bing.net/th/id/R-C.3a1b98d8aa749503cc2ff9c224bc8b40?rik=xxNkH0iChSUYqg&riu=http%3a%2f%2fd.ifengimg.com%2fq100%2fimg1.ugc.ifeng.com%2fnewugc%2f20190119%2f10%2fwemedia%2fabbab6554fa54232bec645b46e6e7bb3f0e4cc5b_size2326_w3000_h2000.JPG&ehk=UzIcp%2fHqCMHntTpDKBDEvAT%2bhhu8xR805ZL0enQCZ%2fY%3d&risl=1&pid=ImgRaw&r=0")
    .override(800, 600)  // 指定分辨率
    .skipMemoryCache(true) // 跳过内存缓存
    .diskCacheStrategy(DiskCacheStrategy.ALL) // 全量磁盘缓存
    .into(imageView)

核心API设计遵循with().load().into()三步式结构,隐藏底层复杂实现。

  • with():绑定生命周期,初始化并返回RequestManager

  • load():指定资源(URL、本地路径、资源ID等),返回RequestBuilder

  • into():触发加载流程,最终显示到Target(通常是ImageView)。

Glide执行流程图

Glide.with(Activity)
     .load(url)
     .into(ImageView)
     │
     ├─ with: 创建 RequestManager(绑定生命周期)
     │   └─ 注入 SupportRequestManagerFragment 监听生命周期
     │
     ├─ load:构建 RequestBuilder(设置 Model 和 Options)
     │
     ├─ into: 创建 ImageViewTarget(包装 ImageView)
     │
     ├─ into: Engine.load()
     │   ├─ 生成 EngineKey(唯一标识请求)
     │   ├─ 检查 Active Resources → 命中则直接返回
     │   ├─ 检查 Memory Cache → 命中则返回并加入 Active
     │   └─ 未命中 → 创建 EngineJob 和 DecodeJob
     │       │
     │       ├─ DecodeJob.run()
     │       │   ├─ 尝试从 RESOURCE_CACHE 加载解码后的资源
     │       │   ├─ 尝试从 DATA_CACHE 加载原始数据
     │       │   ├─ 从 SOURCE(网络/文件)加载数据
     │       │   ├─ 解码数据(使用 BitmapPool 复用)
     │       │   └─ 转码为目标类型(Drawable/Gif)
     │       │
     │       └─ 将结果写入 Active Resources 和 Memory Cache
     │
     └─ into: 主线程回调 onResourceReady() → 显示图片

Glide 初始化(with)

// 初始化调用链示例
Glide.with(context) 
     → Glide.get(context) // 触发GlideBuilder构建实例
     → GlideBuilder.build() 
        → 初始化Engine、Registry、MemoryCache等核心组件
     → RequestManagerRetriever.get() // 注入Fragment并绑定生命周期

单例模式

通过双重校验锁(DCL)实现线程安全的单例初始化,首次调用时触发GlideBuilder.build()

    public static Glide get(Context context) {
        if (glide == null) {
            synchronized (Glide.class) {
                if (glide == null) {
                    //....
                    GlideBuilder builder = new GlideBuilder(applicationContext);
                    for (GlideModule module : modules) {
                        module.applyOptions(applicationContext, builder);
                    }
                    glide = builder.createGlide();
                    for (GlideModule module : modules) {
                        module.registerComponents(applicationContext, glide);
                    }
                }
            }
        }
        return glide;
    }

绑定生命周期

创建透明Fragment以管理Glide生命周期,透明Fragment与外层页面生命周期保持一致。

Glide 通过 Glide.with(context) 中传入的 context 管理生命周期。有以下两种情况:

  • 当传入的context是Activity/Fragment上下文时:

    • Glide会向当前页面注入透明的Fragment(如SupportRequestManagerFragment),该Fragment通过FragmentManager与页面生命周期同步。在onStart/onStop/onDestroy时(LifecycleListener)触发Glide的请求管理(暂停加载或释放资源)。

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
    RequestManagerFragment current = getRequestManagerFragment(fm);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
        requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
        current.setRequestManager(requestManager);
    }
    return requestManager;
}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
        current = pendingRequestManagerFragments.get(fm);
        if (current == null) {
            // 在Activity中注入Fragment
           current = new RequestManagerFragment();
           pendingRequestManagerFragments.put(fm, current);
           fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
            handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
        }
    }
    return current;
}
  • 当传入的context为Application上下文或者在非主线程调用with()时。

    • 绑定应用全局生命周期,直接创建RequestManager对象,适用于后台线程或服务等场景。

    private RequestManager getApplicationManager(Context context) {
        // Either an application context or we're on a background thread.
        if (applicationManager == null) {
            synchronized (this) {
                if (applicationManager == null) {
                    // Normally pause/resume is taken care of by the fragment we add to the fragment or activity.
                    // However, in this case since the manager attached to the application will not receive lifecycle
                    // events, we must force the manager to start resumed using ApplicationLifecycle.
                    applicationManager = new RequestManager(context.getApplicationContext(),
                            new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
                }
            }
        }
        return applicationManager;
    }

核心组件初始化

负责GlideContext,Engine,Registry 等对象的创建,并向 Registry 中注册各种工具类。

  • RequestManager :Glide管理中心。

    • 生命周期管理、请求配置管理、分发调度管理等

    • RequestManager不直接管理 Request,而是交由 RequestTracker 管理 Request 的启动,取消,暂停等。

  • Engine:任务调度与资源管理核心。负责图片加载执行,协调缓存查找、资源加载、线程调度及生命周期管理:

    • 内存缓存管理和磁盘缓存接口(Glide缓存一节阐述)

    • 任务调度器和线程池(Glide加载一节阐述)

  • Registry:组件注册与数据处理中枢。负责扩展能力,用于注册和管理所有数据处理组件,确保灵活支持多种数据源与处理逻辑。

    • ModelLoader:将复杂数据模型(如 URL、File)转换为可解码的数据流(如 InputStream)。

    • ResourceDecoder:将原始数据(如 InputStream)解码为资源(如 BitmapGIF)。

    • Transcoder:转换资源格式(如 BitmapDrawable),通过 BitmapDrawableTranscoder 实现。

Glide 加载(load)

负责匹配数据加载器(ModelLoader),并返回DrawableTypeRequest请求对象。

Glide.with(context)           
    .load(url)                 // 创建RequestBuilder,匹配ModelLoader
     → loadGeneric(String.class) // 根据数据类型选择ModelLoader
     → 创建DrawableTypeRequest<String>实例

选择数据加载器

ModelLoader<T, Data> :将数据模型(T)转换为可解码的数据流(Data)。我们传入的是String,这块加载的是StreamStringLoader,功能是将URL转为InputStream。我们甚至可以自定义ModelLoader。

// RequestManager.java
public DrawableTypeRequest<String> load(String string) {
    return (DrawableTypeRequest<String>) loadGeneric(String.class).load(string);
}

private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
    // 关键步骤:通过Registry匹配ModelLoader
    ModelLoader<T, InputStream> streamLoader = 
        glide.buildStreamModelLoader(modelClass, context);
    ModelLoader<T, ParcelFileDescriptor> fileLoader = 
        glide.buildFileDescriptorModelLoader(modelClass, context);
    
    return new DrawableTypeRequest<>(modelClass, streamLoader, fileLoader, ...);
}

构造请求构建器

DrawableTypeRequest:针对Drawable资源的请求构建器,继承了DrawableRequestBuilder,管理数据加载、解码、转换流程等;

Glide渲染(into)

Glide 的缓存术语:

  1. Active 内存缓存:正在使用的图片对应的内存缓存

  2. Cache 内存缓存:不在使用的图片对应的内存缓存

  3. Data 磁盘缓存:原始数据对应的磁盘缓存

  4. Resource 磁盘缓存:解码后数据对应的磁盘缓存

流程图

加载流程:

  • 请求发起与构建阶段

    • 发起图片加载请求:通过 Glide.with(context).load(uri).into(imageView) 等 API 发起加载

    • 构建 Request 对象:封装加载参数(URL、宽高、转换规则等);生成唯一的请求标识(Key);确定图片加载优先级。

  • 多级缓存检查流程

    • 活动资源缓存(ActiveResources):存储当前正在使用的图片资源(被 View 引用的图片);使用WeakReference+ReferenceQueue实现,避免内存泄漏;优先检查:若图片正在被使用,直接复用资源。未命中处理:进入内存缓存检查。

    • 内存缓存检查(MemoryCache):存储近期使用的图片(LruCache 实现);若活动资源缓存未命中,再检查内存缓存;命中后会将图片转移到活动资源缓存中。

    • 磁盘缓存检查(DiskCache):缓存位置分为SOURCE(原始资源)和RESULT(处理后资源)两种类型;命中处理:从磁盘读取缓存文件,解码图片数据并进入后续处理流程;未命中处理:发起网络请求获取图片。

  • 图片获取与处理阶段
    • 网络请求阶段:使用HttpUrlConnectionOkHttp发起请求;支持断点续传和重试机制;下载图片数据到临时文件。

    • 图片解码与转换

      • 解码流程:使用BitmapFactoryImageDecoder解码图片‘’支持自动判断图片格式(JPEG、PNG、WEBP 等)。

      • 转换处理:按请求参数进行尺寸缩放(override(width, height));应用图片转换(圆角、高斯模糊、旋转等);支持自定义转换接口(Transformation)。

  • 缓存与显示阶段
    • 缓存处理:内存缓存将处理后的图片存入LruCache;活动资源缓存:将正在显示的图片存入ActiveResources;磁盘缓存:将处理后的图片写入磁盘(RESULT类型)。

    • 图片显示:通过ImageViewTarget或自定义 Target 绑定显示组件;支持动画效果(淡入、缩放等);处理图片显示异常(如加载失败、内存不足)。

    • 回调与监听:提供了完整的生命周期回调:onStart():加载开始;onSuccess():加载成功;onError():加载失败;onResourceReady():资源准备完成。

关键机制:

  • 唯一标识(EngineKey):根据请求参数(URL、尺寸、变换、签名等)生成唯一键,确保缓存匹配和请求合并的准确性。

  • 缓存层级与回退:1.查询顺序:Active缓存Memory缓存Resource磁盘缓存Data磁盘缓存。2.逐级回退:优先复用活跃资源,逐级下沉查询,最大限度减少耗时操作。

  • 请求合并:相同 EngineKey 的请求复用回调,避免重复加载和解码,提升性能。

  • 资源释放:1.引用计数:Active缓存 通过引用计数管理资源生命周期,解绑 Target 时计数归零则移入 Memory缓存。2.LRU清理:内存和磁盘缓存按最近最少使用策略淘汰旧资源,防止内存泄漏。

加载阶段:

生成唯一标识(EngineKey)
  • 参数收集:根据 load(url) 的输入参数(URL、尺寸 override(800,600)、转换选项 centerCrop()、签名 signature() 等)生成唯一标识。
  • 哈希计算:将参数组合序列化后,通过 SHA-256 生成哈希值,确保不同参数组合的请求哈希不同。
  • 构建 EngineKey:将哈希值与其他上下文参数(如 Target 类型)合并,生成最终 EngineKey

检查内存缓存
  • ActiveResources 查询:使用 EngineKeyActiveResources(弱引用缓存)中查找正在使用的资源。命中:更新引用计数(acquire()),直接返回资源。未命中:进入 MemoryCache 查询。

  • MemoryCache 查询:使用 EngineKeyLruResourceCache(LRU 内存缓存)中查找。命中:资源移至 ActiveResources,引用计数初始化为 1。未命中:进入磁盘缓存查询。

处理重复请求
  • 旧请求检测:通过 RequestTracker 检查同一 Target 是否已绑定旧请求。
  • 取消旧请求:若旧请求未完成,调用 Request#clear() 释放资源并移除任务队列。
  • 合并新请求:若新旧请求的 EngineKey 相同,直接复用旧请求的回调,避免重复加载。

查询磁盘缓存
  • Resource 缓存查询:根据 EngineKey 的变体(如尺寸调整后的 ResourceCacheKey)查找已解码资源。命中:解码资源并缓存到 ActiveResources。未命中:进入 Data 缓存查询。

  • Data 缓存查询:根据原始数据标识(DataCacheKey)查找未解码的原始数据(如网络响应字节流)。命中:解码数据并应用转换,写入 Resource 缓存(若策略允许)。未命中:触发网络请求。

发起新请求
  • 任务创建:Engine 创建 EngineJob(管理生命周期)和 DecodeJob(执行加载)。
  • 线程池分配:DecodeJob 被提交到 GlideExecutor(磁盘或网络线程池)。
  • 数据加载:
    • 网络请求:通过 HttpUrlFetcher 下载数据,写入 Data 缓存(若策略为 DiskCacheStrategy.DATA)。
    • 本地加载:通过 FileLoader 直接读取文件。
  • 解码与转换:使用 Downsampler 解码数据,应用 Transformation(如 CenterCrop),生成最终资源

缓存更新与资源释放
  • Active缓存写入:新资源通过 Engine#onEngineJobComplete() 加入 ActiveResources

  • Memory缓存淘汰:当资源引用计数归零时(如 Target 解绑),资源移入 MemoryCache

  • LRU 清理:当 MemoryCache 或磁盘缓存达到上限时,按 LRU 规则淘汰旧资

图片显示(主线程回调)

  • 资源就绪通知:DecodeJob 完成解码后,通过 EngineJob#notifyCallbacksOfResult() 通知主线程。

  • 主线程切换:通过 MainThreadExecutor(内部使用 Handler(Looper.getMainLooper()))切换到主线程。

  • 应用资源到 Target:

    • ImageView 显示:调用 ImageViewTarget#onResourceReady(),将资源(如 BitmapDrawable)设置到 ImageView

    • 动画处理:若配置了过渡动画(如 crossFade()),通过 ViewPropertyTransition.animate() 执行动画。

  • 错误与占位符处理:

    • 加载失败:调用 onLoadFailed(),显示错误占位符(通过 error(Drawable) 配置)。

    • 占位符替换:在加载完成前显示 placeholder(Drawable),加载成功后替换。

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

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

相关文章

7.RV1126-OPENCV cvtColor 和 putText

一.cvtColor 1.作用 cvtColor 是 OPENCV 里面颜色转换的转换函数。能够实现 RGB 图像转换成灰度图、灰度图转换成 RGB 图像、RGB 转换成 HSV 等等 2.API CV_EXPORTS_W void cvtColor( InputArray src, OutputArray dst, int code, int dstCn 0 ); 第一个参数&#xff1a;…

Redisson单机模式

redisson调用unlock的过程 Redisson 是一个基于 Redis 的 Java 驻内存数据网格&#xff08;In-Memory Data Grid&#xff09;框架&#xff0c;提供了分布式和可扩展的数据结构和服务。Redisson 的 unlock 方法用于释放锁。下面是 unlock 方法的调用过程&#xff1a; 获取锁的状…

数据结构第6章 图(竟成)

第 6 章 图 【考纲内容】 1.图的基本概念 2.图的存储及基本操作&#xff1a;(1) 邻接矩阵法&#xff1b;(2) 邻接表法&#xff1b;(3) 邻接多重表、十字链表 3.图的遍历&#xff1a;(1) 深度优先搜索&#xff1b;(2) 广度优先搜索 4.图的基本应用&#xff1a;(1) 最小 (代价) 生…

机器人现可完全破解验证码:未来安全技术何去何从?

引言 随着计算机视觉技术的飞速发展&#xff0c;机器学习模型现已能够100%可靠地解决Google的视觉reCAPTCHAv2验证码。这标志着一个时代的结束——自2000年代初以来&#xff0c;CAPTCHA&#xff08;"全自动区分计算机与人类的图灵测试"的缩写&#xff09;一直是区分…

CppCon 2014 学习:(Costless)Software Abstractions for Parallel Architectures

硬件和科学计算的演变关系&#xff1a; 几十年来的硬件进步&#xff1a;计算机硬件不断快速发展&#xff0c;从提升单核速度&#xff0c;到多核并行。科学计算的驱动力&#xff1a;科学计算需求推动硬件创新&#xff0c;比如需要更多计算能力、更高性能。当前的解决方案是并行…

网络爬虫 - App爬虫及代理的使用(十一)

App爬虫及代理的使用 一、App抓包1. App爬虫原理2. reqable的安装与配置1. reqable安装教程2. reqable的配置3. 模拟器的安装与配置1. 夜神模拟器的安装2. 夜神模拟器的配置4. 内联调试及注意事项1. 软件启动顺序2. 开启抓包功能3. reqable面板功能4. 夜神模拟器设置项5. 注意事…

群晖 NAS 如何帮助培训学校解决文件管理难题

在现代教育环境中&#xff0c;数据管理和协同办公的效率直接影响到教学质量和工作流畅性。某培训学校通过引入群晖 NAS&#xff0c;显著提升了部门的协同办公效率。借助群晖的在线协作、自动备份和快照功能&#xff0c;该校不仅解决了数据散乱和丢失的问题&#xff0c;还大幅节…

NLP学习路线图(十八):Word2Vec (CBOW Skip-gram)

自然语言处理&#xff08;NLP&#xff09;的核心挑战在于让机器“理解”人类语言。传统方法依赖独热编码&#xff08;One-hot Encoding&#xff09; 表示单词&#xff0c;但它存在严重缺陷&#xff1a;每个单词被视为孤立的符号&#xff0c;无法捕捉词义关联&#xff08;如“国…

嵌入式学习笔记 - 新版Keil软件模拟时钟Xtal灰色不可更改的问题

在新版Keil软件中&#xff0c;模拟时钟无法修改XTAL频率&#xff0c;默认只能使用12MHz时钟。‌这是因为Keil MDK从5.36版本开始&#xff0c;参数配置界面不再支持修改系统XTAL频率&#xff0c;XTAL选项变为灰色&#xff0c;无法修改。这会导致在软件仿真时出现时间错误的问题&…

黑马Java面试笔记之 集合篇(算法复杂度+ArrayList+)

一. 算法复杂度分析 1.1 时间复杂度 时间复杂度分析&#xff1a;来评估代码的执行耗时的 常见的复杂度表示形式 常见复杂度 1.2 空间复杂度 空间复杂度全称是渐进空间复杂度&#xff0c;表示算法占用的额外存储空间与数据规模之间的增长关系 二. 数组 数组&#xff08;Array&a…

Nginx+Tomcat负载均衡

目录 Tomcat简介 Tomcat 的核心功能 Tomcat架构 Tomcat 的特点 Tomact配置 关闭防火墙及系统内核 Tomcar 主要文件信息 配置文件说明 案例一&#xff1a;Java的Web站点 案例二&#xff1a;NginxTomcat负载均衡、动静分离 Tomcat简介 Tomcat 是由 Apache 软件基金会&am…

【论文解读】ReAct:从思考脱离行动, 到行动反馈思考

认识从实践开始&#xff0c;经过实践得到了理论的认识&#xff0c;还须再回到实践去。 ——《实践论》,毛泽东 1st author: About – Shunyu Yao – 姚顺雨 paper [2210.03629] ReAct: Synergizing Reasoning and Acting in Language ModelsReAct: Synergizing Reasoning and…

简单配置RHEL9.X

切换默认运行级别 将系统默认启动模式从多用户的图形界面调整为多用户的文本界面&#xff0c;适用于优化系统资源占用或进行远程服务器管理的场景。 注意&#xff1a;安装选择“带GUI的服务器”部分常用命令默认安装&#xff1b;如果选择“最小安装”时&#xff0c;部分常用命…

下载并运行自制RAG框架

项目部署 https://github.com/huangjia2019/rag-project01-framework git clone https://github.com/huangjia2019/rag-project01-framework.git 一 、 前端分部分部署 在 Ubuntu 系统 上安装 Node.js 和 npm&#xff08;Node Package Manager&#xff09;&#xff0c;并初始…

Rust 学习笔记:Cargo 工作区

Rust 学习笔记&#xff1a;Cargo 工作区 Rust 学习笔记&#xff1a;Cargo 工作区创建工作区在工作区中创建第二个包依赖于工作区中的外部包向工作区添加测试将工作区中的 crate 发布到 crates.io添加 add_two crate 到工作区总结 Rust 学习笔记&#xff1a;Cargo 工作区 随着项…

颈部的 “异常坚持”

生活中&#xff0c;有些人的颈部会突然变得 “异常坚持”—— 头部不受控制地偏向一侧&#xff0c;或是不自主地旋转、后仰&#xff0c;仿佛被无形的力量牵引着。这种情况不仅影响外观&#xff0c;还会带来强烈的不适感&#xff0c;颈部肌肉紧绷、酸痛&#xff0c;像被一根绳索…

Ubuntu22.04安装MinkowskiEngine

MinkowskiEngine简介 Minkowski引擎是一个用于稀疏张量的自动微分库。它支持所有标准神经网络层&#xff0c;例如对稀疏张量的卷积、池化和广播操作。 MinkowskiEngine安装 官方源码链接&#xff1a;GitHub - NVIDIA/MinkowskiEngine: Minkowski Engine is an auto-diff neu…

【计算机网络】第2章:应用层—应用层协议原理

目录 1. 网络应用的体系结构 2. 客户-服务器&#xff08;C/S&#xff09;体系结构 3. 对等体&#xff08;P2P&#xff09;体系结构 4. C/S 和 P2P 体系结构的混合体 Napster 即时通信 5. 进程通信 6. 分布式进程通信需要解决的问题 7. 问题1&#xff1a;对进程进行编址…

【Zephyr 系列 6】使用 Zephyr + BLE 打造蓝牙广播与连接系统(STEVAL-IDB011V1 实战)

🧠关键词:Zephyr、BLE、广播、连接、GATT、低功耗蓝牙、STEVAL-IDB011V1 📌适合人群:希望基于 Zephyr 实现 BLE 通信的嵌入式工程师、蓝牙产品开发人员 🧭 前言:为什么选择 Zephyr 开发 BLE? 在传统 BLE 开发中,我们大多依赖于厂商 SDK(如 Nordic SDK、BlueNRG SD…

利用 Scrapy 构建高效网页爬虫:框架解析与实战流程

目录 前言1 Scrapy 框架概述1.1 Scrapy 的核心优势1.2 Scrapy 的典型应用场景 2 Scrapy 工作原理解析2.1 框架结构图2.2 Spider&#xff1a;定义数据采集策略2.3 Scheduler&#xff1a;调度请求与去重2.4 Downloader&#xff1a;网页下载器2.5 Item&#xff1a;结构化数据容器2…