结合 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解耦,支持扩展。