当前位置: 首页 > ai >正文

Glide源码解析

前言

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.xdnf.cn/news/9849.html

相关文章:

  • STM32F407VET6学习笔记7:Bootloader跳转APP程序
  • 《仿盒马》app开发技术分享-- 订单列表页(端云一体)
  • 2025年机械化设计制造与计算机工程国际会议(MDMCE 2025)
  • Redis--缓存击穿详解及解决方案
  • 全志V853挂载sd卡
  • 多部手机连接同一wifi的ip一样吗?
  • MC0309魔法项链
  • 多模型数据库(Multi-Model Database)深度解析
  • EasyFileCount(文件查重工具) v3.0.5.1 便携版
  • 有关用easyExcel批量导入excel入库慢的调优记录
  • 深入了解linux系统—— 库的制作和使用
  • 高端装备制造企业如何选择适配的项目管理系统提升项目执行效率?附选型案例
  • Java-代码段-http接口调用自身服务中的其他http接口(mock)-并建立socket连接发送和接收报文实例
  • 生益的高速PCB板材有哪些
  • (二)开启深度学习动手之旅:先筑牢预备知识根基
  • 缓存常见问题:缓存穿透、缓存雪崩以及缓存击穿
  • zynq ad7616 调试笔记
  • 从实验室到商用!铁电液晶如何改写显示技术格局?
  • python 包管理工具uv
  • 国芯思辰| 国产四通道24位生理电采集模拟前端AFE全面替换ADS1294R,心电贴性能再飞跃
  • Docker部署项目无法访问,登录超时完整排查攻略
  • 视频监控联网系统GB28181协议中校时流程详解以及校时失败常见原因
  • 在windows环境下安装Nmap并使用
  • 2025年渗透测试面试题总结-匿名[校招]安全研究员(SAST方向)(题目+回答)
  • 2025国创赛-高教主赛道·创意组评审要点整理
  • set_property LOC约束
  • Qt 无边框窗口实现拖动与窗口控制(最小化/最大化/关闭)
  • 从外卖APP到网络协议:深入解析UDP及应用层协议
  • [python] argparse怎么指定bool类型?
  • ST-GCN