Glide源码解析

article/2025/8/13 7:02:34

前言

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中注入Fragmentcurrent = 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匹配ModelLoaderModelLoader<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.hkcw.cn/article/ZcHOwcqcbZ.shtml

相关文章

01.认识Kubernetes

什么是Kubernets 套用官方文档对Kubernetes的定义&#xff0c;翻译成中文的意思是&#xff1a; Kubernetes&#xff0c;也称为k8&#xff0c;是一个用于自动化部署、扩展和管理容器化应用程序的开源系统。 它将组成应用程序的容器分组为逻辑单元&#xff0c;以便于管理和发现…

印把PL-15残骸给日本 中国有防备吗 国防部回应让16亿人松口气

印巴冲突虽然已经结束20多天,但其影响仍在持续。印度方面将此前获得的PL-15空空导弹残骸交由日本团队研究,外界对此表示担忧,担心技术泄密或被反向研制。针对这一情况,国防部的回应让许多人松了一口气。在印巴冲突期间,两国分别使用中式武器和西式武器进行对抗,展示了各自…

美的集团董事长兼总裁再谈小米 战略上已输

5月30日,美的集团董事长兼总裁方洪波在2024年度股东大会上回应投资者提问时表示,小米进入家电业在战略上已失败。今年小米在空调市场掀起低价竞争,其大家电业务一季度收入同比翻倍增长。此前,方洪波曾表示“在战术上重视小米、在战略上不惧怕小米”。针对这一表述,他解释说…

莫迪想对中企下黑手的动机是什么 稀土牌反制威力显现

莫迪政府试图对中企采取行动,其动机和影响引发关注。莫迪政府的外交政策逐渐极端化,最近要求监控设备商提交硬件、软件和源代码供评估,声称是为了防止所谓的“安全问题”。这显然针对的是中国企业在印度市场的份额,如海康威视、小米和大华等。这种要求无理且超出正常安全审…

余承东展示尊界S800新功能 挥手关门科技感十足

鸿蒙智行的百万级豪华轿车尊界 S800 将于今晚正式发布。华为常务董事、终端BG董事长余承东在微博上持续预热这款新车,并发布了一则新视频,展示了尊界S800挥手关门的新功能。视频中,尊界S800不仅能够自动开门,乘客落座后向内挥手,车门还能自动轻轻关上。此外,视频还展示了…

摄像头探测器APP:守护隐私的防偷拍利器

在当今社会&#xff0c;隐私保护成为越来越多人关注的焦点。无论是入住酒店、民宿&#xff0c;还是在其他公共场所&#xff0c;我们都有可能面临被偷拍的风险。摄像头探测器APP的出现&#xff0c;为用户提供了一种便捷、高效的检测手段&#xff0c;能够有效识别并防范潜在的偷拍…

8天Python从入门到精通【itheima】-54~56

目录 54节-函数传入的参数 1.函数传入数据的定义和功能 2.函数传入参数的实例 3.代码实战 4.形参和实参的概念 5.函数传入参数的注意事项 6.小节总结 55节-案例练习-升级版自动查核酸 1.案例需求 2.代码实战 56节-函数的返回值定义语法 1.学习目标 2.返回值的生活案…

ROS云课基础篇-02-C++-250529

ROS云课基础篇-01-Linux-250529-CSDN博客 基于Zsh的C机器人编程基础实验报告 ——结合AutomaticAddison教程与ROS开发环境 一、实验目标 掌握C基础语法及面向对象编程&#xff08;OOP&#xff09;在机器人开发中的应用配置Zsh终端环境&#xff0c;结合ROS Kinetic实现C机器人…

黄金现货期货双跌 市场避险情绪降温

5月30日,国际黄金价格在经历前一日的回调和反弹后依旧低迷。5月29日,国际黄金市场遭遇显著回调,现货黄金价格盘中一度下探至3245.19美元/盎司,创本周以来新低,COMEX黄金期货价格也同步回落。当天伦敦金现货价格跌破3330美元/盎司,一度触及3245.19美元/盎司的新低。截至当…

青岛即墨通报店铺涉嫌传销 市场监管部门发布情况

本文转自【即墨市场监管】;5月30日,即墨市场监管发布情况通报:责任编辑:0764

成都发生持刀伤人案 警方通报 因感情纠纷引发

成都市公安局锦江区分局5月30日发布警情通报,当天下午3点左右,中纱帽街8号负一层发生一起持刀伤人事件。警方接到报警后迅速赶到现场,并控制了犯罪嫌疑人陆某某,他今年26岁。经初步调查,陆某某因感情纠纷前往前女友胡某某的工作单位。胡某某今年24岁,在与陆某某发生口角后…

A股打破“端午劫”魔咒?专家建议 持股过节乐观看待

5月30日,A股迎来端午节前最后一个交易日,整体走势较为平淡。上证指数、深证成指和创业板指均呈现窄幅震荡,市场涨停个股不足50只。体育、养殖、银行等板块涨幅居前,而近期火爆的可控核聚变概念出现回调。回顾过去十年A股在端午节前后的表现,整体涨少跌多,因此有“端午劫”…

美国防长拿什么来取信亚洲国家 承诺可信度受质疑

第22届香格里拉对话会将于5月30日至6月1日在新加坡举行。美国国防部长赫格塞思计划在会议上发表演讲,阐述美国在“印太地区”的防务政策。自上任以来,赫格塞思主要关注国内问题,抵制军队中的多元、平等与包容政策,并对媒体持批评态度。此次访问亚洲,他将试图向该地区的国防…

App识别安卓系统弹授权框包含某段文字-并自动点击确定按钮

安卓App识别手机系统弹授权框包含某段文字-并自动点击确定按钮 --蓝牙电话App自动部署 上一篇&#xff1a;手机打电话时将对方DTMF数字转为RFC2833发给局域网SIP坐席 下一篇&#xff1a;编写中。 一、前言 蓝牙电话方案中&#xff0c;我们提供了将手机通话的语音拦截后转发到…

上海高考报名人数逆势上涨 招生计划调整引关注

2025年上海秋季高考考生人数预计将超过6万人,比2024年增加近万人。上海市教育考试院透露了这一数据,并表示已经与全国高校沟通在沪招生计划增量。预计今年在沪招生的本科计划数将有所增加,但受限于高校教育资源承载力等因素,本科计划增量不一定能完全匹配生源的增长。对于今…

长了痣到底要不要除掉 专家建议关注“问题痣”

近日,演员孙俪出席时尚芭莎年度派对。亮相时,网友发现她的唇下痣消失了,随后话题#孙俪唇下痣没了#登上热搜。其实,在《甄嬛传》播出期间,孙俪唇下的一个小黑点就引发过观众的关注。到《芈月传》和《那年花开月正圆》播出期间,这颗痣已经成为她面部轮廓的一个标志。然而,…

62岁俞敏洪骑行摔倒受伤:犯困睡着了 网友刷屏关注

5月29日,俞敏洪在青海骑行时不小心摔倒,膝盖等部位受伤出血,引起了许多网友的关注。30日凌晨1点多,俞敏洪发文表示自己只是皮外伤,骨头没有问题,并感谢大家的关心。他在文中写道:“今天骑车有点睡着了,摔了一下,感谢广大朋友关心。皮外伤,不用担心,报平安。”俞敏洪…

德国将向乌提供军援传递何种信号 加大军事支持

乌克兰总统泽连斯基计划于当地时间28日访问德国,期间将与德国总理默茨讨论俄乌和平谈判等议题。默茨表示,德国及其盟友已不再限制提供给乌克兰的武器射程,这使得乌克兰能够攻击俄罗斯本土深处的军事目标。他还强调,德国将继续在军事上支持乌克兰,但未明确是否会向乌方提供…

郑钦文晋级法网16强 状态火热再创佳绩

北京时间5月30日,法国网球公开赛女单第三轮比赛中,郑钦文以2比0战胜18岁加拿大小将姆博科,顺利晋级法网16强。首盘比赛仅耗时36分钟,郑钦文轰出3记ACE球,成功完成两次破发,以6-3率先拿下第一盘。这是郑钦文职业生涯第二次闯入法网16强,在罗兰加洛斯的连胜场次也达到了九…

中行原副行长张小东任新职 或将出任农发行行长

中国农业发展银行官网消息显示,前中国银行副行长张小东已担任农发行党委副书记。经过一系列流程后,张小东或将出任该行新行长。今年3月,在中行2024年度业绩发布会上,张小东表示,2025年中国银行将继续为服务实体经济提供有力金融支持,提升信贷增长质效。预计全年境内人民币…