RequestManager 的 load 源码分析
以下分析的所有源码,都只是部分源码,只为了总体流程分析。
Glide 显示网络图片最简单的代码如下:
Glide.with(this).load(url).into(mImageView);
Glide 的加载流程可以概括为以下流程:
model(数据源)-->data(转换数据)-->decode(解码)-->transformed(缩放)-->transcoded(转码)-->encoded(编码保存到本地)
我们知道 with 方法会返回 requestManager 对象,接下来,我们一步步分析 load 的源码。
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
return asDrawable().load(drawable);
}
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
// resourceClass 就是最终要转码的类型
return new RequestBuilder<>(glide, this, resourceClass, context);
}
load 方法有大量的重载实现,以上源码只展示了部分方法,由上述源码可知,最终调用的是 RequestBuilder 的 load 方法,这个方法也相应有大量的重载方法,下面只展示通过网络地址来加载图片的逻辑。
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
// 并没有马上进入数据请求加载过程,而是简单的将数据进行了保存,并将isModelSet设置为true
this.model = model;
isModelSet = true;
return this;
}
RequestBuilder 的 into 源码分析
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
return into(
// 将会生成 DrawableImageViewTarget
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
首先,会根据 ImageView 设置的缩放类型,配置一个请求参数,该参数会在缩放步骤使用到,重点在于最后的方法,第一个参数 glideContext.buildImageViewTarget(view, transcodeClass) 会根据转码的类型来生成一个 ViewTarget,最终会调用如下方法:
public <Z> ViewTarget<ImageView, Z> buildTarget(
@NonNull ImageView view, @NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
由于这里的类型是 Drawable,所以最终返回一个 DrawableImageViewTarget 对象。我们接着看 into 方法:
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
// 第一步
// 通过isModelSet检查是否通过load设置了数据源,否则抛出异常
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
// 第二步
// 创建请求,Request类是一个接口,他抽象了Glide加载图片请求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
// 第三步
// 3. 判断当前请求是否已经存在
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
//如果是,回收之前创建的 Request
if (!Preconditions.checkNotNull(previous).isRunning()) {
// 直接请求
previous.begin();
}
return target;
}
// 第四步
// 清除target
requestManager.clear(target);
// 将 SingleRequest 对象保存到ViewTarget的Tag中,所以我们的 ImageView 不能再直接调用 setTaget 方法了。
// 如果我们确实需要缓存数据,那么只能调用setTag(int key, Object tag)给tag设置一个key
target.setRequest(request);
// 调用 track 方法开始请求
requestManager.track(target, request);
return target;
}
具体步骤在注释有说明,现在看一下第二步是怎样构建请求的:
// 递归构建请求
private Request buildRequestRecursive(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
ErrorRequestCoordinator errorRequestCoordinator = null;
// 如果设置了请求出错时的备用请求
if (errorBuilder != null) {
// 创建错误请求协调器
errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
// 构造目标请求
Request mainRequest =
buildThumbnailRequestRecursive(
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
if (errorRequestCoordinator == null) {
return mainRequest;
}
int errorOverrideWidth = errorBuilder.getOverrideWidth();
int errorOverrideHeight = errorBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight) && !errorBuilder.isValidOverride()) {
errorOverrideWidth = requestOptions.getOverrideWidth();
errorOverrideHeight = requestOptions.getOverrideHeight();
}
// 错误时的备用请求
Request errorRequest =
errorBuilder.buildRequestRecursive(
target,
targetListener,
errorRequestCoordinator,
errorBuilder.transitionOptions,
errorBuilder.getPriority(),
errorOverrideWidth,
errorOverrideHeight,
errorBuilder,
callbackExecutor);
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
private Request buildThumbnailRequestRecursive(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
// 如果设置了缩略图的备用请求
if (thumbnailBuilder != null) {
if (isThumbnailBuilt) {
throw new IllegalStateException(
"You cannot use a request as both the main request and a "
+ "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
}
// 设置 transitionOptions
TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
thumbnailBuilder.transitionOptions;
if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
thumbTransitionOptions = transitionOptions;
}
// 优先级
Priority thumbPriority =
thumbnailBuilder.isPrioritySet()
? thumbnailBuilder.getPriority()
: getThumbnailPriority(priority);
// 图片尺寸
int thumbOverrideWidth = thumbnailBuilder.getOverrideWidth();
int thumbOverrideHeight = thumbnailBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !thumbnailBuilder.isValidOverride()) {
thumbOverrideWidth = requestOptions.getOverrideWidth();
thumbOverrideHeight = requestOptions.getOverrideHeight();
}
// 创建缩略图请求协调器
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
// 目标请求
Request fullRequest =
obtainRequest(
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
isThumbnailBuilt = true;
// Recursively generate thumbnail requests.
// 缩略图的请求
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(
target,
targetListener,
coordinator,
thumbTransitionOptions,
thumbPriority,
thumbOverrideWidth,
thumbOverrideHeight,
thumbnailBuilder,
callbackExecutor);
isThumbnailBuilt = false;
// 把目标请求和缩略图请求放进协调器里,来协调各类型图片间的请求顺序
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
} else if (thumbSizeMultiplier != null) {
// Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest =
obtainRequest(
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
BaseRequestOptions<?> thumbnailOptions =
requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);
Request thumbnailRequest =
obtainRequest(
target,
targetListener,
thumbnailOptions,
coordinator,
transitionOptions,
getThumbnailPriority(priority),
overrideWidth,
overrideHeight,
callbackExecutor);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
// Base case: no thumbnail.
// 没有缩略图时,构造请求
return obtainRequest(
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
}
}
构建请求的方法是递归方法,会视情况递归地构建多个请求,为什么会有多个请求呢?因为 Glide 允许你设置请求目标请求失败时的备用请求和缩略图请求,具体描述如下:
- 错误图片请求(正常的请求出错时,如果有配置该请求,则启动该请求)
- 缩略图请求(小图请求,可以较快显示。如有配置,在请求开始时,就会启动)
- 目标图片请求(目标图片请求,在请求开始时,就是启动)
如果除了目标图片外,用户还配置了错误图片显示,或缩略图显示,那么,这时候会创建一个请求协调器,来协调各类型图片间的请求顺序。为了简化流程,我们这里只看目标请求,即没有设置请求目标请求失败时的备用请求和缩略图请求的情况,最终会调用如下方法来构建请求对象。
public static <R> SingleRequest<R> obtain(
Context context,
GlideContext glideContext,
Object model,
Class<R> transcodeClass,
BaseRequestOptions<?> requestOptions,
int overrideWidth,
int overrideHeight,
Priority priority,
Target<R> target,
RequestListener<R> targetListener,
@Nullable List<RequestListener<R>> requestListeners,
RequestCoordinator requestCoordinator,
Engine engine,
TransitionFactory<? super R> animationFactory,
Executor callbackExecutor) {
@SuppressWarnings("unchecked")
SingleRequest<R> request = (SingleRequest<R>) POOL.acquire();
if (request == null) {
// 创建了一个 SingleRequest 对象
request = new SingleRequest<>();
}
// 初始化赋值,注意赋值参数
request.init(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
engine,
animationFactory,
callbackExecutor);
return request;
}
到此,into 方法第二步构建请求对象分析完成,我们接着分析第四步,调用了 RequestManager 对象的 track 方法:
// RequestManager.java
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
// 开始请求
requestTracker.runRequest(request);
}
接着调用 RequestTracker 的 runRequest 方法:
public void runRequest(@NonNull Request request) {
// 将请求放到集合里
requests.add(request);
// 不是暂停状态
if (!isPaused) {
// 开始请求
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
// 添加到请求列表中
pendingRequests.add(request);
}
}
至此,通过 SingleRequest 的 begin 方法来开始加载请求任务:
public synchronized void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
// model 为空
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
// 加载错误的处理
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
if (status == Status.COMPLETE) {
// 请求加载完成后会回调
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// 如果图片显示尺寸有效,直接回调 onSizeReady
onSizeReady(overrideWidth, overrideHeight);
} else {
// 根据 target 的宽高来加载图片的宽高
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
// 开始请求,显示加载占位图
target.onLoadStarted(getPlaceholderDrawable());
}
}
如果 model 为空,也就是我们传入的图片地址为空,则会调用 onLoadFailed 方法,在该方法会先回调监听器的失败回调,然后又调用了 setErrorPlaceholder 方法,接着看看该方法中做了什么操作。
private synchronized void setErrorPlaceholder() {
if (!canNotifyStatusChanged()) {
return;
}
Drawable error = null;
// 传入的地址为空
if (model == null) {
// 获取 fallback 资源
error = getFallbackDrawable();
}
// 如果没有设置 fallback 资源
if (error == null) {
// 获取 error 资源
error = getErrorDrawable();
}
// 如果没有设置 error 资源
if (error == null) {
// 获取 placeholder 资源
error = getPlaceholderDrawable();
}
target.onLoadFailed(error);
}
如果我们传入图片地址为空,则首先查看是否有后备回调符设置,然后是错误占位符,最后是加载占位符,最终调用 target.onLoadFailed 方法,也就是 ImageViewTarget 的 onLoadFailed 方法。
public void onLoadFailed(@Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
setResourceInternal(null);
// 加载失败后设置的 Drawable
setDrawable(errorDrawable);
}
在 begin 方法里还有 target.onLoadStarted(getPlaceholderDrawable()) 代码用来正常显示加载任务时的占位符。当获取到有效的图片尺寸后,会回调 onSizeReady() 方法。
public synchronized void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
loadStatus =
// 加载图片并返回状态
// engine 对象的在实例化 Glide 对象时由 GlideBuilder 创建的 (GlideBuilder创建了所有的默认配置选项)
engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this,
callbackExecutor);
if (status != Status.RUNNING) {
loadStatus = null;
}
}
上述方法,调用了 engine 的 load 方法来加载请求任务。
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 isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
// 创建资源索引 KEY
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
// 如果可以从内存缓存中获取,则先获取内存缓存的
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
// 内存缓存的数据为空
if (memoryResource == null) {
return waitForExistingOrStartNewJob(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
options,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache,
cb,
callbackExecutor,
key,
startTime);
}
}
// 直接拿内存缓存的数据并回调加载完成,传入的类型为 MEMORY_CACHE
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
}
上述方法先根据 KEY 来获取内存缓存数据,如果内存,则直接回调成功,如果不存在,则调用 waitForExistingOrStartNewJob 方法做进一步处理。
先来看一下从内存缓存中取数据的代码:
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
if (!isMemoryCacheable) {
return null;
}
// 从内存中当前正在显示的资源缓存加载图片
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return active;
}
// 从内存缓存资源中加载图片
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return cached;
}
return null;
}
如果要加载的图片已经正在显示,直接使用已有的资源。如果图片没有在显示,但是已经正好还在内存缓存中,没有被销毁,那么直接使用缓存中的资源。
我们再看 waitForExistingOrStartNewJob 的方法:
private <R> LoadStatus waitForExistingOrStartNewJob(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor,
EngineKey key,
long startTime) {
// 获取已经存在的加载任务 ,onlyRetrieveFromCache 参数表示是否只加载缓存中的数据
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
// 添加 SingleRequest 回调对象
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
// 构造 EngineJob 对象,用于启动解码任务
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
// 构造 DecodeJob 对象,是一个 Runnable 对象,真正执行数据加载和解码的类
DecodeJob<R> decodeJob =
// 将EngineJob传入,用于回调
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
// 缓存加载任务
jobs.put(key, engineJob);
// 添加 SingleRequest 回调对象
engineJob.addCallback(cb, callbackExecutor);
// 执行解码任务
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
上述方法最终会调用 engineJob 的 start 方法从网络或者本地硬盘中去加载一张图片。
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
// GlideExecutor就是一个线程池执行器(Executor),有各种方法获得缓存线程池,还有资源线程池(SourceExecutor)
// start 方法就是用来在线程池中启动DecodeJob这个Runnable对象,
// 也就是说EngineJob的主要作用是开启线程来加载图片
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
executor.execute(decodeJob);
}
DecodeJob 是一个继承 Runnable 的类,任务启动的入口就在run方法中,最终会调用 runWrapped 方法。
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
然后会调用下面这些方法:
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
// 处理过的缓存资源加载器
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
// 原始图片资源缓存加载器
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
// 远程图片资源加载器
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
// 循环调用了 startNext 方法
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
上述的这几个方法构成了 Glide 的解码流程,分为三步:
- 尝试从处理过的本地资源加载图片。
- 尝试从未处理过的原始本地资源加载图片。
- 尝试从远程加载图片。
这是一个嵌套的循环,通过状态的切换来寻找下一个加载器,直到加载一张图片,返回成功;或者找不到要加载的图片,返回失败。我们从最后一个SourceGenerator加载器入手,因为,当你第一次加载一张新的网络图片时,本地并没有这张网络图片的缓存。从runGenerators方法中看到,Generator的入口是startNext()方法:
public boolean startNext() {
// 1. 判断是否有缓存
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
// 缓存数据
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
// 没有缓存,从远程加载
loadData = null;
boolean started = false;
// 2. 遍历所有的ModelLoader模块加载器
while (!started && hasNextModelLoader()) {
// 关键代码 ,拿到 HttpGlideUrlLoader 对象
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
// 调用 HttpUrlFetcher 的 loadData 方法
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
我们直接看从远程中加载,其中调用了 DecodeHelper 的 getLoadData() 方法:
//DecodeHelper.java
List<LoadData<?>> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
// 获取所有的 ModelLoader 对象
List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = modelLoaders.size(); i < size; i++) {
ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
LoadData<?> current = modelLoader.buildLoadData(model, width, height, options);
if (current != null) {
loadData.add(current);
}
}
}
return loadData;
}
上述代码最终会通过 ModelLoaderRegistry 类的 getModelLoaders 方法获取 model 类型对应的数据转换器ModelLoader。
回到 startNext 方法,最终返回的是 HttpGlideUrlLoader 对象,然后调用 HttpGlideUrlLoader 的 fetcher (HttpUrlFetcher) 的 loadData 方法。
// HttpUrlFetcher.java
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
// 调用自身的 loadDataWithRedirects 方法
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
// 成功回调
callback.onDataReady(result);
} catch (IOException e) {
// 失败回调
callback.onLoadFailed(e);
} finally {
}
}
上述方法又会调用 loadDataWithRedirects 方法,利用 HttpURLConnection 来获取网络图片的 InputStream 对象。最后通过 callback.onDataReady(result) 将结果回调给 SourceGenerator 进行下一步处理。
// SourceGenerator.java
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
// 赋值给一个缓存对象(重点),重启任务的时候会在 startNext再次判断这个对象
dataToCache = data;
// We might be being called back on someone else's thread. Before doing anything, we should
// reschedule to get back onto Glide's thread.
// 重启 DecodeJob 任务
cb.reschedule();
} else {
// 不处理缓存,回调 DecodeJob 的 onDataFetcherReady 方法
cb.onDataFetcherReady(
loadData.sourceKey,
data,
loadData.fetcher,
loadData.fetcher.getDataSource(),
originalKey);
}
}
获取到数据后,分两种情况,一是需要将图片缓存到本地硬盘,一种是不需要缓存。Glide配置了多种缓存策略,默认是自动智能切换缓存存储策略,Glide认为远程网络图片获取是昂贵的,所以默认网络图片是会缓存原图的。而本地图片,包括drawable/assets等是不会缓存原图的。(当然你也可以重新配置)
进入if后,会将数据保存起来(留意dataToCache),然后重启任务。
//DecodeJob.java
@Override
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
//EngineJob.java
@Override
public void reschedule(DecodeJob<?> job) {
getActiveSourceExecutor().execute(job);
}
最终又会回到 SourceGenerator 的 startNext 方法中。
public boolean startNext() {
// 1. 判断是否有缓存
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
// 缓存数据
cacheData(data);
}
// 省略代码...
}
此时 dataToCache 将不再是 null 的,所以会将数据缓存到本地硬盘,并启动另一个加载器DataCacheGenerator,而这个Generator正是用来加载缓存在本地的图片的。
而DataCacheGenerator和ResourceCacheGenerator的原理与SourceGenerator基本是一致的,只不过一个用来加载原始的本地缓存图,另一个用来加载处理过的本地缓存。最终还是会回调 DecodeJob 的 onDataFetcherReady 方法。
public void onDataFetcherReady(
Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;
// 将请求返回的 InputStream 流赋值给 currentData
this.currentData = data;
this.currentFetcher = fetcher;
this.currentDataSource = dataSource;
this.currentAttemptingKey = attemptedKey;
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
// 关键代码,解码数据
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
至此,整个数据模型转换和数据抓取流程分析完毕,下面来总结一下:
- Glide利用线程池的方式,将每一个解码过程都封装为一次解码任务。
- 整个数据抓取过程中,Glide会尝试从内存到处理过的图片缓存,再到原图缓存,最后到远程图片等四个地方进行数据加载。(这里的远程图片包括drawable/assets等资源)
- 数据模型转换时,根据Glide初始化时注册的模型转换注册表,将原始model模型数据转换为可能的数据模型,并尝试使用这些模型来抓取数据,直至抓取到数据,或抓取失败返回。