Glide 4.x 版本的图片加载流程

结合 Glide 的源码(基于 Glide 4.x 版本,因为这是目前最广泛使用的版本)详细讲解图片加载的完整流程。Glide 是一个高效、灵活的图片加载库,其核心在于异步加载、缓存管理和资源优化。以下是图片加载流程的详细分解,涵盖关键源码和实现原理。


1. Glide 初始化与请求起点

图片加载的起点是调用 Glide.with(context),这是 Glide 的入口方法,用于创建加载请求的上下文环境。

源码分析:Glide.with()

java 复制代码
public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
}
  • 作用Glide.with() 获取或创建一个 RequestManager 实例,RequestManager 是管理图片加载请求的核心类。
  • 实现细节
    • getRetriever(context) 返回一个 RequestManagerRetriever,负责管理 RequestManager 的生命周期。
    • 根据传入的 context 类型(ActivityFragmentApplication),Glide 会绑定生命周期(如 Activity 的 onDestroy),确保资源在适当时候释放。
    • 如果是 Application 上下文,Glide 使用一个无生命周期的 RequestManager,适合全局加载。

关键点

  • Glide 使用 FragmentSupportRequestManagerFragmentRequestManagerFragment)来监听 Activity/Fragment 的生命周期,确保加载请求在组件销毁时暂停或取消。
  • 源码中,RequestManager 内部维护了一个 RequestTracker,用于跟踪和管理所有请求。

2. 构建请求:load() 和配置

调用 Glide.with(context).load(url) 开始构建加载请求。load() 方法接收图片资源(如 URL、文件路径、资源 ID 等)。

源码分析:load()

java 复制代码
public RequestBuilder<Drawable> load(@Nullable String string) {
    return asDrawable().load(string);
}
  • 作用load() 返回一个 RequestBuilder 实例,用于配置加载请求的参数(如占位图、错误图、变换等)。
  • 实现细节
    • asDrawable() 指定加载的目标资源类型(默认是 Drawable,也可以是 BitmapGif)。
    • load(String) 将图片的 URI 或路径存储到 RequestBuilder 中,供后续处理。

配置选项

开发者可以通过链式调用配置加载选项,例如:

java 复制代码
Glide.with(context)
    .load(url)
    .placeholder(R.drawable.placeholder)
    .error(R.drawable.error)
    .thumbnail(0.25f)
    .diskCacheStrategy(DiskCacheStrategy.ALL)
    .into(imageView);
  • 这些配置会存储在 RequestBuilder 和底层的 RequestOptions 中,影响加载流程的各个阶段。

3. 触发加载:into()

调用 into(ImageView) 是触发图片加载的最终步骤,Glide 在此将请求提交到后台线程执行。

源码分析:into()

java 复制代码
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    // 构建 Target
    ViewTarget<ImageView, TranscodeType> target = buildImageViewTarget(view, transcodeClass);
    // 提交请求
    return into(target);
}
  • 作用into() 创建一个 ViewTarget(通常是 ImageViewTarget),并将加载任务提交给 Glide 的执行引擎。
  • 实现细节
    • buildImageViewTarget 根据目标类型(DrawableBitmap)创建相应的 Target
    • into(Target) 调用 RequestBuilder.into(Target),启动加载流程。

关键点

  • Target 是 Glide 中用于接收加载结果的接口,ImageViewTarget 负责将加载的图片设置到 ImageView 上。
  • into() 内部,Glide 会检查 ImageView 的当前状态(如尺寸),并根据需要延迟加载(等待布局完成)。

4. 请求执行:Engine 核心

RequestBuilder.into() 最终将请求交给 Engine 类,Engine 是 Glide 的核心调度器,负责管理加载任务和缓存。

源码分析:Engine.load()

java 复制代码
public <R> LoadStatus load(
    GlideContext glideContext,
    Object model,
    Key signature,
    int width,
    int height,
    Class<?> resourceClass,
    Class<R> transcodeClass,
    Priority priority,
    DiskCacheStrategy diskCacheStrategy,
    Map<Class<?>, Transformation<?>> transformations,
    boolean isMemoryCacheable,
    boolean useUnlimitedSourceExecutor,
    boolean useAnimationPool,
    boolean onlyRetrieveFromCache,
    Options options,
    EngineJobListener callback) {
    // 检查缓存
    EngineResource<?> cached = memoryCache.get(key);
    if (cached != null) {
        callback.onResourceReady(cached);
        return null;
    }
    // 创建 EngineJob
    EngineJob<R> engineJob = engineJobFactory.build(...);
    // 提交到线程池
    engineJob.start(decodeJob);
}
  • 作用Engine.load() 负责检查缓存、创建加载任务并提交到线程池。
  • 实现细节
    1. 缓存检查
      • 首先检查内存缓存(memoryCache),如果命中,直接返回缓存资源。
      • 如果未命中,检查磁盘缓存(DiskLruCache)或发起网络请求。
    2. 任务创建
      • 创建 EngineJob,负责协调加载任务的执行。
      • 创建 DecodeJob,负责实际的资源解码和处理。
    3. 线程池提交
      • 根据优先级(Priority)和配置,任务被提交到 sourceExecutor(网络加载)或 diskCacheExecutor(缓存加载)。

5. 资源获取与解码:DecodeJob

DecodeJob 是执行图片加载和解码的核心类,负责从缓存或网络获取资源并进行解码。

源码分析:DecodeJob.run()

java 复制代码
void run() {
    try {
        if (onlyRetrieveFromCache) {
            resource = decodeFromCache();
        } else {
            resource = decodeFromRetriever();
        }
    } catch (Throwable t) {
        notifyFailed(t);
    }
}
  • 作用DecodeJob 根据配置决定从缓存还是网络加载资源。
  • 实现细节
    1. 缓存加载decodeFromCache):
      • 检查磁盘缓存(DiskLruCache),如果命中,调用 DataFetcher 解码数据。
      • 磁盘缓存使用 LRU 算法,存储原始数据或转换后的资源。
    2. 网络加载decodeFromRetriever):
      • 使用 DataFetcher(如 HttpUrlFetcher)从网络获取数据。
      • 数据流通过 InputStream 传递给解码器(如 BitmapDecoderGifDecoder)。
    3. 解码与转换
      • 解码后,资源可能经过 Transformation(如圆角、裁剪)处理。
      • 最终生成 BitmapDrawableGifDrawable

6. 缓存管理

Glide 的缓存机制是其高效性的关键,分为内存缓存和磁盘缓存。

内存缓存

  • 使用 LruResourceCache(基于 LRU 算法的内存缓存)存储加载完成的资源。

  • ActiveResources 存储正在使用的资源,防止被 GC 回收。

  • 源码:

    java 复制代码
    memoryCache.put(key, resource);

磁盘缓存

  • 使用 DiskLruCache 存储原始数据或转换后的资源。

  • 配置通过 DiskCacheStrategy 控制(如 ALLDATARESOURCE)。

  • 源码:

    java 复制代码
    diskCache.put(key, writer);

7. 结果回调与显示

加载完成后,EngineJob 通过回调将结果传递给 Target

源码分析:EngineJob.onResourceReady()

java 复制代码
void onResourceReady(Resource<R> resource, DataSource dataSource) {
    mainThreadCallback.onResourceReady(resource, dataSource);
}
  • 作用 :将加载的资源传递到主线程,调用 Target.onResourceReady()
  • 实现细节
    • ImageViewTarget 接收资源并调用 setImageDrawable()setImageBitmap()
    • 如果配置了占位图或错误图,Glide 会根据加载状态显示相应图片。

8. 生命周期管理

Glide 通过 RequestManager 绑定生命周期,确保资源管理高效:

  • 当 Activity/Fragment 暂停时,RequestManager.pauseRequests() 暂停所有请求。
  • 当销毁时,RequestManager.clearRequests() 取消所有请求并释放资源。

源码分析:RequestManager.onStart()

java 复制代码
public void onStart() {
    resumeRequests();
}

总结:Glide 图片加载流程

  1. 初始化Glide.with() 创建 RequestManager,绑定生命周期。 GPR
  2. 请求构建load() 和配置选项(如 placeholderdiskCacheStrategy)生成 RequestBuilder
  3. 触发加载into() 创建 Target 并提交请求。
  4. 任务调度Engine 检查缓存,创建 EngineJobDecodeJob
  5. 资源获取DecodeJob 从缓存或网络加载数据,解码并应用转换。
  6. 缓存管理 :内存缓存(LruResourceCache)和磁盘缓存(DiskLruCache)优化性能。
  7. 结果显示 :资源通过 Target 显示到 ImageView
  8. 生命周期:绑定组件生命周期,自动暂停/取消请求。

关键优化与设计亮点

  • 三级缓存 :内存缓存(LruResourceCacheActiveResources)、磁盘缓存(DiskLruCache)、网络加载。
  • 线程池管理 :使用 ExecutorService 区分网络和磁盘任务,优化并发。
  • 资源复用 :通过 BitmapPool 复用 Bitmap,减少内存分配。
  • 模块化设计DataFetcherDecoderTransformation 解耦,支持扩展。
相关推荐
李白的粉6 分钟前
基于springboot的在线教育系统
java·spring boot·毕业设计·课程设计·在线教育系统·源代码
码农10087号19 分钟前
Hot100方法及易错点总结2
java
iuyou️1 小时前
Spring Boot知识点详解
java·spring boot·后端
北辰浮光1 小时前
[Mybatis-plus]
java·开发语言·mybatis
一弓虽1 小时前
SpringBoot 学习
java·spring boot·后端·学习
南客先生1 小时前
互联网大厂Java面试:RocketMQ、RabbitMQ与Kafka的深度解析
java·面试·kafka·rabbitmq·rocketmq·消息中间件
ai大佬1 小时前
Java 开发玩转 MCP:从 Claude 自动化到 Spring AI Alibaba 生态整合
java·spring·自动化·api中转·apikey
Mr__Miss2 小时前
面试踩过的坑
java·开发语言
爱喝一杯白开水2 小时前
POI从入门到上手(一)-轻松完成Apache POI使用,完成Excel导入导出.
java·poi
向哆哆2 小时前
Java 安全:如何防止 DDoS 攻击?
java·安全·ddos