结合 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
类型(Activity
、Fragment
或Application
),Glide 会绑定生命周期(如 Activity 的onDestroy
),确保资源在适当时候释放。 - 如果是
Application
上下文,Glide 使用一个无生命周期的RequestManager
,适合全局加载。
关键点:
- Glide 使用
Fragment
(SupportRequestManagerFragment
或RequestManagerFragment
)来监听 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
,也可以是Bitmap
或Gif
)。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
根据目标类型(Drawable
或Bitmap
)创建相应的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()
负责检查缓存、创建加载任务并提交到线程池。 - 实现细节 :
- 缓存检查 :
- 首先检查内存缓存(
memoryCache
),如果命中,直接返回缓存资源。 - 如果未命中,检查磁盘缓存(
DiskLruCache
)或发起网络请求。
- 首先检查内存缓存(
- 任务创建 :
- 创建
EngineJob
,负责协调加载任务的执行。 - 创建
DecodeJob
,负责实际的资源解码和处理。
- 创建
- 线程池提交 :
- 根据优先级(
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
根据配置决定从缓存还是网络加载资源。 - 实现细节 :
- 缓存加载 (
decodeFromCache
):- 检查磁盘缓存(
DiskLruCache
),如果命中,调用DataFetcher
解码数据。 - 磁盘缓存使用 LRU 算法,存储原始数据或转换后的资源。
- 检查磁盘缓存(
- 网络加载 (
decodeFromRetriever
):- 使用
DataFetcher
(如HttpUrlFetcher
)从网络获取数据。 - 数据流通过
InputStream
传递给解码器(如BitmapDecoder
或GifDecoder
)。
- 使用
- 解码与转换 :
- 解码后,资源可能经过
Transformation
(如圆角、裁剪)处理。 - 最终生成
Bitmap
、Drawable
或GifDrawable
。
- 解码后,资源可能经过
- 缓存加载 (
6. 缓存管理
Glide 的缓存机制是其高效性的关键,分为内存缓存和磁盘缓存。
内存缓存:
-
使用
LruResourceCache
(基于 LRU 算法的内存缓存)存储加载完成的资源。 -
ActiveResources
存储正在使用的资源,防止被 GC 回收。 -
源码:
javamemoryCache.put(key, resource);
磁盘缓存:
-
使用
DiskLruCache
存储原始数据或转换后的资源。 -
配置通过
DiskCacheStrategy
控制(如ALL
、DATA
、RESOURCE
)。 -
源码:
javadiskCache.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 图片加载流程
- 初始化 :
Glide.with()
创建RequestManager
,绑定生命周期。 GPR - 请求构建 :
load()
和配置选项(如placeholder
、diskCacheStrategy
)生成RequestBuilder
。 - 触发加载 :
into()
创建Target
并提交请求。 - 任务调度 :
Engine
检查缓存,创建EngineJob
和DecodeJob
。 - 资源获取 :
DecodeJob
从缓存或网络加载数据,解码并应用转换。 - 缓存管理 :内存缓存(
LruResourceCache
)和磁盘缓存(DiskLruCache
)优化性能。 - 结果显示 :资源通过
Target
显示到ImageView
。 - 生命周期:绑定组件生命周期,自动暂停/取消请求。
关键优化与设计亮点
- 三级缓存 :内存缓存(
LruResourceCache
和ActiveResources
)、磁盘缓存(DiskLruCache
)、网络加载。 - 线程池管理 :使用
ExecutorService
区分网络和磁盘任务,优化并发。 - 资源复用 :通过
BitmapPool
复用Bitmap
,减少内存分配。 - 模块化设计 :
DataFetcher
、Decoder
和Transformation
解耦,支持扩展。