Glide源码解析

前言

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

基本使用

复制代码
dependencies {
    compile 'com.github.bumptech.glide:glide:3.7.0'
}

<uses-permission android:name="android.permission.INTERNET" />
java 复制代码
// 基础用法:加载网络图片
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执行流程图

java 复制代码
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)

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

单例模式

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

Kotlin 复制代码
    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的请求管理(暂停加载或释放资源)。
Kotlin 复制代码
@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对象,适用于后台线程或服务等场景。
Kotlin 复制代码
    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请求对象。

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

选择数据加载器

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

Kotlin 复制代码
// 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),加载成功后替换。

相关推荐
锐湃2 天前
使用glide 同步获取图片
glide
每次的天空12 天前
Android-Glide学习总结
android·学习·glide
CYRUS STUDIO17 天前
FART 主动调用组件设计和源码分析
android·逆向·源码分析·fart·脱壳
每次的天空21 天前
Android学习总结之Glide自定义三级缓存(面试篇)
android·学习·glide
WenGyyyL1 个月前
《Android 应用开发基础教程》——第十一章:Android 中的图片加载与缓存(Glide 使用详解)
android·缓存·glide
microhex1 个月前
Glide 如何加载远程 Base64 图片
java·开发语言·glide
8931519601 个月前
Android开发Glide做毛玻璃效果
android·glide·android开发·android教程·glide做毛玻璃效果
每次的天空1 个月前
Android学习总结之Glide篇(缓存和生命周期)
android·学习·glide
卑微小文2 个月前
Scrapy+Redis:如何用代理IP池突破反爬机制
intellij idea·glide