本篇作为Glide源码分析的开篇,以最简单的方式使用Glide,分析,最终图片是如何显示到ImageView上的。
Glide 版本:4.12.0
先说下结论:
- 首先获取View的宽高信息,通过ViewTreeObserver 的addOnPreDrawListener,在View将要绘制之前返回宽高信息。
- onSizeReady之后,先尝试使用 ResourceCacheGenerator 从包含对原始数据应用了采样或者变换(downsampled/transformed)的磁盘缓存获取。
- 尝试DataCacheGenerator 从没有修改过的原始磁盘缓存文件获取。
- 使用 SourceGenerator 从网络下载源数据。根据磁盘缓存策略,源数据可能首先被写入磁盘,然后从缓存文件加载,而不是直接返回。
- 有了磁盘缓存以后,再次使用 DataCacheGenerator 从没有修改过的原始磁盘缓存文件获取。这个时候就可以获取到数据并返回了。(猜测在这个过程中,还会做transform相关的操作,并把操作后的结果缓存到文件,这块没有去看。)
- 再次加载同一张图片,内存中已经有缓存了,直接从缓存获取返回。
最简单的使用方式
/**
* 最简单的使用方式
*/
private void sourceCodeTest() {
Glide.with(this)
.load(Images.imageUrls[1])
.into(imageView1);
}
with 方法返回的是 RequestManager 对象。
RequestManager 的 load 方法。
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
RequestManager 的 asDrawable 方法。
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
最终是构建了一个 RequestBuilder 对象。
RequestBuilder 的 load方法。
@NonNull
private RequestBuilder <TranscodeType> loadGeneric(@Nullable Object model) {
if(isAutoCloneEnabled()) {
return clone().loadGeneric(model);
}
//model 就是 要加载的图片链接
this.model = model;
//将 isModelSet 置为true
isModelSet = true;
//最终返回了RequestBuilder本身,没有什么特殊的设置
return selfOrThrowIfLocked();
}
RequestBuilder 的 into 方法
@NonNull
public ViewTarget <ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions <?> requestOptions = this;
//注释1处,如果没有设置Transformation && 允许Transformation && view 的 ScaleType 不为null,则获取 requestOptions 对象。
if(!requestOptions.isTransformationSet() && requestOptions.isTransformationAllowed() &&
view.getScaleType() != null) {
// Clone in this method so that if we use this RequestBuilder to load into a View and then
// into a different target, we don't retain the transformation applied based on the previous
// View's scale type.
//在此方法中进行克隆,这样,如果我们使用此RequestBuilder加载到一个View中,然后加载到另一个目标中,
//则不会保留基于上一个视图的缩放类型应用的转换。
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.
}
}
//注释2处,调用重载的 into 方法
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/
null,
requestOptions,
Executors.mainThreadExecutor());
}
注释1处,如果没有设置Transformation && 允许Transformation && view 的 ScaleType 不为null,则获取 requestOptions 对象。
注释2处,调用重载的 into 方法。
RequestBuilder 的 into 方法。
private <Y extends Target<TranscodeType>> Y into(@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options, Executor callbackExecutor) {
//注释1处,在我们的例子中,target 是 DrawableImageViewTarget 对象。
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//注释2处,构建request,我们先忽略其中的细节
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
//注释3处,如果有和之前的请求相同的请求,并且不是跳过内存缓存的请求,则使用之前的请求。
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
//注释4处,取消Glide可能为此target的所有未完成的加载,并释放可能已为目标加载的任何资源(例如{@link Bitmap}),以便可以重用它们。
//注意:这里内部会清除Glide为Target设置的Tag。
requestManager.clear(target);
//注释5处,给target重新设置tag
target.setRequest(request);
//注释6处,跟踪请求
requestManager.track(target, request);
return target;
}
注释1处,在我们的例子中,target 是 DrawableImageViewTarget 对象。
注释2处,构建request,我们先忽略其中的细节。返回的是一个 SingleRequest 对象。
注释3处,如果有和之前的请求相同的请求,并且不是跳过内存缓存的请求,则使用之前的请求。我们先忽略这种情况。
注释4处,取消Glide可能为此 target 的所有未完成的加载,并释放可能已为目标加载的任何资源(例如{@link Bitmap}),以便可以重用它们。 注意:这里内部会清除Glide为Target设置的Tag。
RequestManager 的 clear 方法。这块细节先略过。分析Glide在RecyclerView中应用的时候, 再详细分析。
注释5处,清除tag以后,给target重新设置tag。这个是保证不乱序的原因。
ViewTarget 的setRequest方法。
@Override
public void setRequest(@Nullable Request request) {
setTag(request);
}
//tagId
private static int tagId = R.id.glide_custom_view_target_tag;
private void setTag(@Nullable Object tag) {
//清除的时候,会将Tag设置为null。
isTagUsedAtLeastOnce = true;
view.setTag(tagId, tag);
}
RequestBuilder 的 into 方法注释6处, RequestManager 调用 track 方法。
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
//调用 RequestTracker 的 runRequest 方法
requestTracker.runRequest(request);
}
RequestTracker 的 runRequest 方法。
public void runRequest(@NonNull Request request) {
requests.add(request);
if(!isPaused) {
//注释1处,调用 SingleRequest 的 begin 方法。
request.begin();
} else {
request.clear();
if(Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
注释1处,调用 SingleRequest 的 begin 方法。
@Override
public void begin() {
synchronized(requestLock) {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if(model == null) {
if(Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
// Only log at more verbose log levels if the user has set a fallback drawable, because
// fallback Drawables indicate the user expects null models occasionally.
int logLevel = getFallbackDrawable() == null ? Log.WARN :
Log.DEBUG;
onLoadFailed(new GlideException("Received null model"),
logLevel);
return;
}
if(status == Status.RUNNING) {
throw new IllegalArgumentException(
"Cannot restart a running request");
}
// If we're restarted after we're complete (usually via something like a notifyDataSetChanged
// that starts an identical request into the same Target or View), we can simply use the
// resource and size we retrieved the last time around and skip obtaining a new size, starting
// a new load etc. This does mean that users who want to restart a load because they expect
// that the view size has changed will need to explicitly clear the View or Target before
// starting the new load.
if(status == Status.COMPLETE) {
onResourceReady(
resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */
false);
return;
}
// Restarts for requests that are neither complete nor running can be treated as new requests
// and can run again from the beginning.
//注释1处,开始状态是 WAITING_FOR_SIZE,等待控件测量过后有尺寸
status = Status.WAITING_FOR_SIZE;
if(Util.isValidDimensions(overrideWidth, overrideHeight)) {
//注释2处,如果指定了宽高,直接调用onSizeReady方法。
onSizeReady(overrideWidth, overrideHeight);
} else {
//注释3处,否则,调用Target的getSize方法。SingleRequest 本身做为回调传入
target.getSize(this);
}
if((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE) &&
canNotifyStatusChanged()) {
//先给ImageView 设置placeholderDrawable
target.onLoadStarted(getPlaceholderDrawable());
}
if(IS_VERBOSE_LOGGABLE) {
logV("finished run method in " + LogTime.getElapsedMillis(
startTime));
}
}
}
注释1处,开始状态是 WAITING_FOR_SIZE,等待控件测量过后有宽高信息。
注释2处,如果指定了宽高,直接调用onSizeReady方法。
注释3处,否则,调用Target的getSize方法。SingleRequest 本身做为回调传入。内部是调用 SizeDeterminer 的 getSize 方法。
void getSize(@NonNull SizeReadyCallback cb) {
int currentWidth = getTargetWidth();
int currentHeight = getTargetHeight();
if(isViewStateAndSizeValid(currentWidth, currentHeight)) {
//如果有宽高信息了,直接回调 onSizeReady 方法
cb.onSizeReady(currentWidth, currentHeight);
return;
}
//没有宽高信息,叫回调cb添加到列表中,等待获取到宽高信息后,通知回调cb。
if(!cbs.contains(cb)) {
cbs.add(cb);
}
if(layoutListener == null) {
ViewTreeObserver observer = view.getViewTreeObserver();
layoutListener = new SizeDeterminerLayoutListener(this);
//注释1处,添加监听,监听尺寸的变化,在View绘制之前会执行这个layoutListener,此时已经有宽高信息了。
observer.addOnPreDrawListener(layoutListener);
}
}
注释1处,添加监听,监听尺寸的变化,在View绘制之前会执行这个layoutListener,此时已经有宽高信息了。
ViewTarget.SizeDeterminer.SizeDeterminerLayoutListener 类
private static final class SizeDeterminerLayoutListener
implements ViewTreeObserver.OnPreDrawListener {
private final WeakReference <SizeDeterminer> sizeDeterminerRef;
SizeDeterminerLayoutListener(@NonNull SizeDeterminer sizeDeterminer) {
sizeDeterminerRef = new WeakReference <> (sizeDeterminer);
}
@Override
public boolean onPreDraw() {
SizeDeterminer sizeDeterminer = sizeDeterminerRef.get();
if(sizeDeterminer != null) {
//注释1处,调用 SizeDeterminer 的 checkCurrentDimens 方法。
sizeDeterminer.checkCurrentDimens();
}
return true;
}
}
注释1处,获取大调用 SizeDeterminer 的 checkCurrentDimens 方法。
@Synthetic
void checkCurrentDimens() {
if(cbs.isEmpty()) {
return;
}
//注释1处,注意,getTartgetWidth和getTargetHeight方法
int currentWidth = getTargetWidth();
int currentHeight = getTargetHeight();
if(!isViewStateAndSizeValid(currentWidth, currentHeight)) {
//注释2处,宽高不合法,说明此时View还没有经过measure,直接返回,SizeDeterminerLayoutListener不会被清除。
//等待经过measure后,再次调用checkCurrentDimens方法。
return;
}
//注释3处,如果宽高合法通知回调,并清除监听SizeDeterminerLayoutListener。
notifyCbs(currentWidth, currentHeight);
clearCallbacksAndListener();
}
注释1处,注意,SizeDeterminer 的 getTargetWidth 和 getTargetHeight 方法。
private int getTargetWidth() {
int horizontalPadding = view.getPaddingLeft() + view.getPaddingRight();
LayoutParams layoutParams = view.getLayoutParams();
int layoutParamSize = layoutParams != null ? layoutParams.width :
PENDING_SIZE;
return getTargetDimen(view.getWidth(), layoutParamSize,
horizontalPadding);
}
SizeDeterminer 的 getTargetDimen 方法。
private int getTargetDimen(int viewSize, int paramSize, int paddingSize) {
int adjustedParamSize = paramSize - paddingSize;
if(adjustedParamSize > 0) {
return adjustedParamSize;
}
if(waitForLayout && view.isLayoutRequested()) {
return PENDING_SIZE;
}
int adjustedViewSize = viewSize - paddingSize;
if(adjustedViewSize > 0) {
return adjustedViewSize;
}
if(!view.isLayoutRequested() && paramSize == LayoutParams.WRAP_CONTENT) {
//注释1处,获取屏幕的宽高中最大者,作为尺寸
return getMaxDisplayLength(view.getContext());
}
// If the layout parameters are < padding, the view size is < padding, or the layout
// parameters are set to match_parent or wrap_content and no layout has occurred, we should
// wait for layout and repeat.
return PENDING_SIZE;
}
注释1处,注意一下,如果无法正确获取View的宽或者高,则获取屏幕的宽高中最大者,作为尺寸。
回到 SizeDeterminer 的 checkCurrentDimens 方法的注释2处,如果宽高不合法,说明此时View还没有经过measure,直接返回,SizeDeterminerLayoutListener 不会被清除。等待经过 measure 后,再次调用 checkCurrentDimens 方法。
注释3处,如果宽高合法,回调 onSizeReady 方法,并清除监听 SizeDeterminerLayoutListener。
获取到尺寸以后,回到 SingleRequest 的 onSizeReady 方法。
@Override
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized(requestLock) {
if(status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
//注释1处,调用Engine的load方法,开始加载图片
loadStatus =
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;
}
}
}
注释1处,调用 Engine 的 load 方法,开始加载图片。
/**
* 开始加载给定参数的资源。
*
* <p>必须在主线程上调用。
*
* <p>任何请求的流程如下:
*
* <ul>
* <li>检查当前的活动资源集,如果存在则返回活动资源,并将任何新的非活动资源移动到内存缓存中。
* <li>检查内存缓存并提供缓存的资源(如果存在)。
* <li>检查当前的进行中的加载,并将cb添加到进行中的加载(如果存在)。
* <li>开始新的加载。
* </ul>
*
* <p>活动资源是那些已经提供给至少一个请求并且尚未释放的资源。一旦资源的所有消费者都释放了该资源,该资源就会进入缓存。如果资源从缓存中返回给新的消费者,它将被重新添加到活动资源中。如果资源从缓存中被逐出,其资源将被回收并在可能的情况下重用,资源将被丢弃。消费者没有严格的要求释放他们的资源,所以活动资源被弱引用持有。
*
* @param width 目标资源的目标宽度(以像素为单位)。
* @param height 目标资源的目标高度(以像素为单位)。
* @param cb 当加载完成时将被调用的回调。
*/
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;
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
//注释1处,先从内存加载
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
//注释2处,内存为null,检查当前的进行中的加载,并将cb添加到进行中的加载(如果存在)。不存在的话,开始新的加载。
return waitForExistingOrStartNewJob(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
options,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache,
cb,
callbackExecutor,
key,
startTime);
}
}
//注释3处,内存存在的话,会直接回调onResourceReady方法
cb.onResourceReady(
memoryResource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
return null;
}
注释1处,先从内存加载 。
注释3处,内存存在的话,会直接回调onResourceReady方法
注释2处,内存为null,检查当前的进行中的加载,并将cb添加到进行中的加载(如果存在)。不存在的话,开始新的加载。
Engine 的 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) {
//注释1处,存在正在进行的加载,将cb添加到进行中的加载,直接返回。
EngineJob <?> current = jobs.get(key, onlyRetrieveFromCache);
if(current != null) {
current.addCallback(cb, callbackExecutor);
if(VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
//构建一个加载任务对象
EngineJob <R> engineJob =engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
//构建一个解析对象,负责从缓存或者原始资源解析并应用transformations 和 transcodes
DecodeJob <R> decodeJob = decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb, callbackExecutor);
//注释2处,开始加载的地方
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
注释1处,存在正在进行的加载,将cb添加到进行中的加载,直接返回。
注释2处,开始加载的地方 EngineJob 的 start 方法
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
//调用 GlideExecutor 的 execute 方法
executor.execute(decodeJob);
}
GlideExecutor 的 execute 方法
@Override
public void execute(@NonNull Runnable command) {
delegate.execute(command);
}
最终会执行 传入的 DecodeJob 的 run 方法
@Override
public void run() {
// This should be much more fine grained, but since Java's thread pool implementation silently
// swallows all otherwise fatal exceptions, this will at least make it obvious to developers
// that something is failing.
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
// Methods in the try statement can invalidate currentFetcher, so set a local variable here to
// ensure that the fetcher is cleaned up either way.
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
//注释1处,调用 runWrapped 方法
runWrapped();
} catch (CallbackException e) {
// If a callback not controlled by Glide throws an exception, we should avoid the Glide
// specific debug logic below.
throw e;
} catch (Throwable t) {
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
throw t;
} finally {
// Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call
// close in all cases anyway.
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
注释1处,调用 DecodeJob 的 runWrapped 方法。
private void runWrapped() {
switch(runReason) {
case INITIALIZE:
//注释1处,INITIALIZE 的下一个状态 RESOURCE_CACHE;
//下一个生成器 ResourceCacheGenerator
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);
}
}
注释1处,INITIALIZE 的下一个状态 RESOURCE_CACHE; 下一个生成器 ResourceCacheGenerator(这个貌似是负责从磁盘获取的操作)。
然后调用 DecodeJob 的 runGenerators 方法
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
//注释1处,循环调用 startNext 方法
while(!isCancelled && currentGenerator != null && !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if(stage == Stage.SOURCE) {
reschedule();
return;
}
}
// We've run out of stages and generators, give up.
if((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
// Otherwise a generator started a new load and we expect to be called back in
// onDataFetcherReady.
}
注释1处,循环调用 startNext 方法。
第一次进入循环,调用 ResourceCacheGenerator 的 startNext 方法。
ResourceCacheGenerator:Generates DataFetchers from cache files containing downsampled/transformed resource data.
@Override
public boolean startNext() {
List <Key> sourceIds = helper.getCacheKeys();
if(sourceIds.isEmpty()) {
return false;
}
/**
* 注册的资源类有
* 1. class com.bumptech.glide.load.resource.gif.GifDrawable
* 2. class android.graphics.Bitmap
* 3. class android.graphics.drawable.BitmapDrawable
*/
List <Class <?>> resourceClasses = helper.getRegisteredResourceClasses();
//...
while(modelLoaders == null || !hasNextModelLoader()) {
resourceClassIndex++;
if(resourceClassIndex >= resourceClasses.size()) {
sourceIdIndex++;
if(sourceIdIndex >= sourceIds.size()) {
//注释0处,最后返回了false,这个时候是没有磁盘缓存的。
return false;
}
resourceClassIndex = 0;
}
//注释1处,sourceId 就是图片地址
Key sourceId = sourceIds.get(sourceIdIndex);
Class <?> resourceClass = resourceClasses.get(resourceClassIndex);
Transformation <? > transformation = helper.getTransformation(resourceClass);
// PMD.AvoidInstantiatingObjectsInLoops Each iteration is comparatively expensive anyway,
// we only run until the first one succeeds, the loop runs for only a limited
// number of iterations on the order of 10-20 in the worst case.
currentKey =
new ResourceCacheKey( // NOPMD AvoidInstantiatingObjectsInLoops
helper.getArrayPool(),
sourceId,
helper.getSignature(),
helper.getWidth(),
helper.getHeight(),
transformation,
resourceClass,
helper.getOptions());
//注释2处,获取缓存的磁盘文件
cacheFile = helper.getDiskCache().get(currentKey);
if(cacheFile != null) {
sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
loadData = null;
boolean started = false;
while(!started && hasNextModelLoader()) {
ModelLoader < File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(
cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
if(loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
经过debug,这个方法在注释0处,最后返回了false,这个时候是没有磁盘缓存的。
回到 DecodeJob 的 runGenerators 方法,继续循环调用 startNext 方法。
下一个阶段 DATA_CACHE,调用 DataCacheGenerator 的 startNext 方法。
DataCacheGenerator:Generates DataFetchers from cache files containing original unmodified source data.
@Override
public boolean startNext() {
while(modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if(sourceIdIndex >= cacheKeys.size()) {
//注释0处,
return false;
}
//sourceId 是 图片url
Key sourceId = cacheKeys.get(sourceIdIndex);
// PMD.AvoidInstantiatingObjectsInLoops The loop iterates a limited number of times
// and the actions it performs are much more expensive than a single allocation.
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
//获取磁盘文件
cacheFile = helper.getDiskCache().get(originalKey);
if(cacheFile != null) {
this.sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
loadData = null;
boolean started = false;
while(!started && hasNextModelLoader()) {
ModelLoader < File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(
cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
if(loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
经过debug,这个方法最后在注释0处返回了false。
回到 DecodeJob 的 runGenerators 方法,继续循环调用 startNext 方法。下一个阶段 SOURCE,currentGenerator 是 SourceGenerator
如果是 SOURCE 阶段,调用 reschedule 方法。
@Override
public void reschedule() {
//runReason 变成了 SWITCH_TO_SOURCE_SERVICE;
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
//重新执行
callback.reschedule(this);
}
最终还是会调用 DecodeJob 的 runGenerators 方法,这个时候 runReason 变成了 SWITCH_TO_SOURCE_SERVICE 。
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
//注释1处,循环调用 startNext 方法
while(!isCancelled && currentGenerator != null && !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if(stage == Stage.SOURCE) {
reschedule();
return;
}
}
// We've run out of stages and generators, give up.
if((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
// Otherwise a generator started a new load and we expect to be called back in
// onDataFetcherReady.
}
注释1处,循环调用 startNext 方法。这时候调用的是 SourceGenerator 的 startNext 方法。
SourceGenerator
类的注释翻译为:使用注册的 ModelLoader
和提供的 model,从原始源数据生成 DataFetcher
。
根据磁盘缓存策略,源数据可能首先被写入磁盘,然后从缓存文件加载,而不是直接返回。
@Override
public boolean startNext() {
if(dataToCache != null) {
//注释1处,此时不存在要缓存的数据
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if(sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while(!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if(loadData != null && (helper.getDiskCacheStrategy().isDataCacheable(
loadData.fetcher.getDataSource()) ||
helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
//注释1处,startNextLoad 方法
startNextLoad(loadData);
}
}
//返回true
return started;
}
注释1处,调用 SourceGenerator 的 startNextLoad 方法
private void startNextLoad(final LoadData <?> toStart) {
// 注释1处,调用 MultiModelLoader.MultiFetcher 的 loadData 方法。
loadData.fetcher.loadData(helper.getPriority(),new DataCallback <Object> () {
@Override
public void onDataReady(@Nullable Object data) {
if(isCurrentRequest(toStart)) {
//加载成功
onDataReadyInternal(toStart, data);
}
}
@Override
public void onLoadFailed(@NonNull Exception e) {
if(isCurrentRequest(toStart)) {
//加载失败
onLoadFailedInternal(toStart, e);
}
}
});
}
注释1处,调用 MultiModelLoader.MultiFetcher 的 loadData 方法。
@Override
public void loadData(@NonNull Priority priority, @NonNull DataCallback <?super Data>
callback) {
this.priority = priority;
this.callback = callback;
exceptions = throwableListPool.acquire();
//注释1处,调用 OkHttpStreamFetcher 的 loadData 方法。 回调是 MultiModelLoader.MultiFetcher 对象
fetchers.get(currentIndex).loadData(priority, this);
if(isCancelled) {
cancel();
}
}
注释1处,调用 OkHttpStreamFetcher 的 loadData 方法,从网络获取数据。
@Override
public void loadData(@NonNull Priority priority, @NonNull final DataCallback <?super InputStream> callback) {
Request.Builder requestBuilder = new Request.Builder().url(url.toStringUrl());
for(Map.Entry < String, String > headerEntry: url.getHeaders().entrySet()) {
String key = headerEntry.getKey();
requestBuilder.addHeader(key, headerEntry.getValue());
}
Request request = requestBuilder.build();
this.callback = callback;
//注释1处,构建一个请求,并加入到请求队列中。
call = client.newCall(request);
//回调是 OkHttpStreamFetcher 对象
call.enqueue(this);
}
请求成功以后,回调 OkHttpStreamFetcher 的 onResponse 方法。
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
responseBody = response.body();
if(response.isSuccessful()) {
long contentLength = Preconditions.checkNotNull(responseBody).contentLength();
stream = ContentLengthInputStream.obtain(responseBody.byteStream(),
contentLength);
//注释1处,回调 MultiModelLoader.MultiFetcher 的 onDataReady 方法。
callback.onDataReady(stream);
} else {
callback.onLoadFailed(new HttpException(response.message(),
response.code()));
}
}
注释1处,回调 MultiModelLoader.MultiFetcher 的 onDataReady 方法
@Override
public void onDataReady(@Nullable Data data) {
if(data != null) {
//注释1处,最终会回调到 SourceGenerator 的 onDataReadyInternal 方法。
callback.onDataReady(data);
} else {
startNextOrFail();
}
}
注释1处,最终会回调到 SourceGenerator 的 onDataReadyInternal 方法。
@Synthetic
void onDataReadyInternal(LoadData <?> loadData, Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if(data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
//注释0处,给 dataToCache 赋值,这个时候,有需要缓存的数据了
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.
//注释2处,再次调用 DecodeJob 的 reschedule 方法。
cb.reschedule();
} else {
cb.onDataFetcherReady(
loadData.sourceKey,
data,
loadData.fetcher,
loadData.fetcher.getDataSource(),
originalKey);
}
}
注释0处,给 dataToCache 赋值,这个时候,有需要缓存的数据了。
注释1处,再次调用 DecodeJob 的 reschedule 方法。
最终还是会调用 DecodeJob 的 runGenerators 方法
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
//注释1处,循环调用 startNext 方法
while(!isCancelled && currentGenerator != null && !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if(stage == Stage.SOURCE) {
reschedule();
return;
}
}
// We've run out of stages and generators, give up.
if((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
注释1处,循环调用 startNext 方法。这时候调用的是 SourceGenerator 的 startNext 方法。
@Override
public boolean startNext() {
if(dataToCache != null) {
//注释1处,这时候,dataToCache 不为空,调用 cacheData 方法。调用 cacheData 方法。
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
//注释2处
if(sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while(!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if(loadData != null && (helper.getDiskCacheStrategy().isDataCacheable(
loadData.fetcher.getDataSource()) || helper.hasLoadPath(
loadData.fetcher.getDataClass()))) {
started = true;
startNextLoad(loadData);
}
}
return started;
}
注释1处,这时候,dataToCache 不为空,调用 cacheData 方法。
private void cacheData(Object dataToCache) {
long startTime = LogTime.getLogTime();
try {
//返回的是 StreamEncoder
Encoder <Object> encoder = helper.getSourceEncoder(dataToCache);
DataCacheWriter <Object> writer =
new DataCacheWriter <> (encoder, dataToCache, helper.getOptions());
originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
//注释1处,调用 DiskLruCacheWrapper 的 put 方法。
helper.getDiskCache().put(originalKey, writer);
} finally {
loadData.fetcher.cleanup();
}
//注释2处,缓存完数据以后,构建了一个 DataCacheGenerator 对象。后面会用这个对象来加载缓存数据。
sourceCacheGenerator =
new DataCacheGenerator(Collections.singletonList(loadData.sourceKey),
helper, this);
}
注释1处,调用 DiskLruCacheWrapper 的 put 方法。
@Override
public void put(Key key, Writer writer) {
// We want to make sure that puts block so that data is available when put completes. We may
// actually not write any data if we find that data is written by the time we acquire the lock.
String safeKey = safeKeyGenerator.getSafeKey(key);
writeLocker.acquire(safeKey);
try {
if(Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Put: Obtained: " + safeKey + " for for Key: " + key);
}
try {
// We assume we only need to put once, so if data was written while we were trying to get
// the lock, we can simply abort.
DiskLruCache diskCache = getDiskCache();
Value current = diskCache.get(safeKey);
if(current != null) {
return;
}
DiskLruCache.Editor editor = diskCache.edit(safeKey);
if(editor == null) {
throw new IllegalStateException(
"Had two simultaneous puts for: " + safeKey);
}
try {
//注释1处,构建文件,写入文件文件名类似
// /data/user/0/com.hm.bitmaploadexample/cache/image_manager_disk_cache/2829dd349db5d3f90cf167007f009b7b7c5e3cba8168ba2cd3d4ad6cb52d65d9.0.tmp
File file = editor.getFile(0);
if(writer.write(file)) {
editor.commit();
}
} finally {
editor.abortUnlessCommitted();
}
} catch(IOException e) {
if(Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unable to put to disk cache", e);
}
}
} finally {
writeLocker.release(safeKey);
}
}
注释1处,构建文件,写入文件。文件名类似 /data/user/0/com.hm.bitmaploadexample/cache/image_manager_disk_cache/2829dd349db5d3f90cf167007f009b7b7c5e3cba8168ba2cd3d4ad6cb52d65d9.0.tmp
。写入文件,就是把 ContentLengthInputStream 流对象写入到文件。
cacheData 方法注释2处,缓存完数据以后,构建了一个 DataCacheGenerator 对象。后面在 SourceGenerator 的 startNext方法注释2处 判断 sourceCacheGenerator 不为null,
会用这个对象继续来 startNext ,从而加载缓存数据。
DataCacheGenerator 的 startNext 方法
@Override
public boolean startNext() {
while(modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if(sourceIdIndex >= cacheKeys.size()) {
return false;
}
//图片url
Key sourceId = cacheKeys.get(sourceIdIndex);
// PMD.AvoidInstantiatingObjectsInLoops The loop iterates a limited number of times
// and the actions it performs are much more expensive than a single allocation.
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
//注释1处,这里从磁盘缓存中获取缓存文件就不为null了。
cacheFile = helper.getDiskCache().get(originalKey);
if(cacheFile != null) {
this.sourceKey = sourceId;
/**
* 这里的modelLoaders 是一个 List<ModelLoader<File, ?>> 对象。
* 1. ByteBufferFileLoader
* 2. FileLoader
* 3. FileLoader
* 4. UnitModelLoader
*
*/
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
loadData = null;
boolean started = false;
while(!started && hasNextModelLoader()) {
ModelLoader < File, ?> modelLoader = modelLoaders.get(
modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(
cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions()
);
if(loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
//注释1处,调用 ByteBufferFileLoader.ByteBufferFetcher 的 loadData 方法。
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
//注释2处,返回true
return started;
}
注释1处,调用 ByteBufferFileLoader.ByteBufferFetcher 的 loadData 方法。回调是 DataCacheGenerator 对象。
@Override
public void loadData(@NonNull Priority priority, @NonNull DataCallback <? super ByteBuffer> callback) {
ByteBuffer result;
try {
//缓存文件是:
// /data/user/0/com.hm.bitmaploadexample/cache/image_manager_disk_cache/7d2fca3704dc60f2da82b3484e656e6e35bee407249878dea160c8809af902f1.0
result = ByteBufferUtil.fromFile(file);
//回调 DataCacheGenerator 对象的 onDataReady 方法。
callback.onDataReady(result);
} catch(IOException e) {
if(Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to obtain ByteBuffer for file", e);
}
callback.onLoadFailed(e);
}
}
DataCacheGenerator 对象的 onDataReady 方法。
@Override
public void onDataReady(Object data) {
//回调 SourceGenerator 对象的 onDataFetcherReady 方法。
cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
}
SourceGenerator 对象的 onDataFetcherReady 方法。
@Override
public void onDataFetcherReady(
Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
// This data fetcher will be loading from a File and provide the wrong data source, so override
// with the data source of the original fetcher
//调用 MultiModelLoader.MultiFetcher 的 getDataSources 方法。
//然后回调到 DecodeJob 的 onDataFetcherReady 方法。
cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
}
DecodeJob 的 onDataFetcherReady 方法。
@Override
public void onDataFetcherReady(
Key sourceKey, Object data, DataFetcher <? > fetcher, DataSource dataSource,
Key attemptedKey) {
this.currentSourceKey = sourceKey;
//data 是一个 java.nio.DirectByteBuffer[pos=0 lim=437344 cap=437344] 对象
this.currentData = data;
this.currentFetcher = fetcher;
this.currentDataSource = dataSource;
this.currentAttemptingKey = attemptedKey;
this.isLoadingFromAlternateCacheKey = sourceKey != decodeHelper.getCacheKeys()
.get(0);
if(Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
//注释1处,解析数据
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
注释1处,解析数据 DecodeJob 的 decodeFromRetrievedData 方法。
private void decodeFromRetrievedData() {
Resource <R> resource = null;
try {
//注释1处,调用 DecodeJob 的 decodeFromData 方法。
resource = decodeFromData(currentFetcher, currentData,
currentDataSource);
} catch(GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if(resource != null) {
//注释2处,调用 DecodeJob 的 notifyEncodeAndRelease 方法。
notifyEncodeAndRelease(resource, currentDataSource,
isLoadingFromAlternateCacheKey);
} else {
runGenerators();
}
}
注释1处,调用 DecodeJob 的 decodeFromData 方法。
private <Data> Resource<R> decodeFromData(
DataFetcher<?> fetcher, Data data, DataSource dataSource) throws GlideException {
try {
if (data == null) {
return null;
}
long startTime = LogTime.getLogTime();
//注释1处,调用 DecodeJob 的 decodeFromFetcher 方法。
Resource<R> result = decodeFromFetcher(data, dataSource);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded result " + result, startTime);
}
//注释2处,最终返回的是 LazyBitmapDrawableResource 对象。
return result;
} finally {
fetcher.cleanup();
}
}
在我们的例子中,最终会调用 ByteBufferBitmapDecoder 的 decode 方法。
@Override
public Resource <Bitmap> decode(@NonNull ByteBuffer source, int width, int height, @NonNull Options options)
throws IOException {
InputStream is = ByteBufferUtil.toStream(source);
return downsampler.decode(is, width, height, options);
}
注释2处,最终返回的是 LazyBitmapDrawableResource 对象。
解析完毕后,回到 decodeFromRetrievedData 方法 注释2处,调用 DecodeJob 的 notifyEncodeAndRelease 方法。
private void notifyEncodeAndRelease(
Resource <R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey
) {
if(resource instanceof Initializable) {
((Initializable) resource).initialize();
}
Resource <R> result = resource;
LockedResource <R> lockedResource = null;
if(deferredEncodeManager.hasResourceToEncode()) {
lockedResource = LockedResource.obtain(resource);
result = lockedResource;
}
//注释1处,调用 DecodeJob 的 notifyComplete 方法。通知成功
notifyComplete(result, dataSource, isLoadedFromAlternateCacheKey);
stage = Stage.ENCODE;
try {
if(deferredEncodeManager.hasResourceToEncode()) {
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
if(lockedResource != null) {
lockedResource.unlock();
}
}
// Call onEncodeComplete outside the finally block so that it's not called if the encode process
// throws.
onEncodeComplete();
}
注释1处,调用 DecodeJob 的 notifyComplete 方法。通知成功
private void notifyComplete(
Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
setNotifiedOrThrow();
//回调 EngineJob 的 onResourceReady 方法。
callback.onResourceReady(resource, dataSource, isLoadedFromAlternateCacheKey);
}
EngineJob 的 onResourceReady 方法。
@Override
public void onResourceReady(
Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
synchronized (this) {
this.resource = resource;
this.dataSource = dataSource;
this.isLoadedFromAlternateCacheKey = isLoadedFromAlternateCacheKey;
}
//注释1处,调用 EngineJob 的 notifyCallbacksOfResult 方法。
notifyCallbacksOfResult();
}
注释1处,调用 EngineJob 的 notifyCallbacksOfResult 方法。
@Synthetic
void notifyCallbacksOfResult() {
ResourceCallbacksAndExecutors copy;
Key localKey;
EngineResource <?> localResource;
synchronized(this) {
stateVerifier.throwIfRecycled();
if(isCancelled) {
// TODO: Seems like we might as well put this in the memory cache instead of just recycling
// it since we've gotten this far...
resource.recycle();
release();
return;
} else if(cbs.isEmpty()) {
throw new IllegalStateException(
"Received a resource without any callbacks to notify"
);
} else if(hasResource) {
throw new IllegalStateException("Already have resource");
}
engineResource = engineResourceFactory.build(resource,
isCacheable, key, resourceListener);
// Hold on to resource for duration of our callbacks below so we don't recycle it in the
// middle of notifying if it synchronously released by one of the callbacks. Acquire it under
// a lock here so that any newly added callback that executes before the next locked section
// below can't recycle the resource before we call the callbacks.
hasResource = true;
copy = cbs.copy();
incrementPendingCallbacks(copy.size() + 1);
localKey = key;
localResource = engineResource;
}
engineJobListener.onEngineJobComplete(this, localKey, localResource);
for(final ResourceCallbackAndExecutor entry: copy) {
//注释1处,这里最终会调用 SingleRequest 的 onResourceReady 方法。
entry.executor.execute(new CallResourceReady(entry.cb));
}
decrementPendingCallbacks();
}
注释1处,这里最终会调用 SingleRequest 的 onResourceReady 方法。
@Override
public void onResourceReady(
Resource<?> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
stateVerifier.throwIfRecycled();
Resource<?> toRelease = null;
try {
synchronized (requestLock) {
loadStatus = null;
if (resource == null) {
GlideException exception =
new GlideException(
"Expected to receive a Resource<R> with an "
+ "object of "
+ transcodeClass
+ " inside, but instead got null.");
onLoadFailed(exception);
return;
}
Object received = resource.get();
if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
toRelease = resource;
this.resource = null;
GlideException exception =
new GlideException(
"Expected to receive an object of "
+ transcodeClass
+ " but instead"
+ " got "
+ (received != null ? received.getClass() : "")
+ "{"
+ received
+ "} inside"
+ " "
+ "Resource{"
+ resource
+ "}."
+ (received != null
? ""
: " "
+ "To indicate failure return a null Resource "
+ "object, rather than a Resource object containing null data."));
onLoadFailed(exception);
return;
}
if (!canSetResource()) {
toRelease = resource;
this.resource = null;
// We can't put the status to complete before asking canSetResource().
status = Status.COMPLETE;
return;
}
//注释1处,调用重载的 onResourceReady 方法。
onResourceReady(
(Resource<R>) resource, (R) received, dataSource, isLoadedFromAlternateCacheKey);
}
} finally {
if (toRelease != null) {
engine.release(toRelease);
}
}
}
注释1处,调用重载的 onResourceReady 方法。
private void onResourceReady(
Resource <R> resource, R result, DataSource dataSource, boolean isAlternateCacheKey) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
if(glideContext.getLogLevel() <= Log.DEBUG) {
Log.d(
GLIDE_TAG,
"Finished loading " + result.getClass().getSimpleName() +
" from " + dataSource + " for " + model + " with size [" +
width + "x" + height + "] in " + LogTime.getElapsedMillis(
startTime) + " ms");
}
isCallingCallbacks = true;
try {
boolean anyListenerHandledUpdatingTarget = false;
if(requestListeners != null) {
for(RequestListener < R > listener: requestListeners) {
anyListenerHandledUpdatingTarget |=
listener.onResourceReady(result, model, target,
dataSource, isFirstResource);
}
}
anyListenerHandledUpdatingTarget |=
targetListener != null && targetListener.onResourceReady(result,
model, target, dataSource, isFirstResource);
if(!anyListenerHandledUpdatingTarget) {
Transition <? super R > animation = animationFactory.build(
dataSource, isFirstResource);
//注释1处,回调 DrawableImageViewTarget 的 onResourceReady 方法。
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
注释1处,回调 DrawableImageViewTarget 的 onResourceReady 方法。会走到父类 ImageViewTarget 的 onResourceReady 方法。
ImageViewTarget 的 onResourceReady 方法。
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition <? super Z >
transition) {
if(transition == null || !transition.transition(resource, this)) {
//注释1处,调用 setResourceInternal 方法。
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
ImageViewTarget 的 setResourceInternal 方法。
private void setResourceInternal(@Nullable Z resource) {
// Order matters here. Set the resource first to make sure that the Drawable has a valid and
// non-null Callback before starting it.
//注释1处,调用 DrawableImageViewTarget 的 setResource 方法。
setResource(resource);
maybeUpdateAnimatable(resource);
}
注释1处,调用 DrawableImageViewTarget 的 setResource 方法。
@Override
protected void setResource(@Nullable Drawable resource) {
//这里最终给 ImageView 设置了resource,是一个BitmapDrawable。
view.setImageDrawable(resource);
}
这里最终给 ImageView 设置了resource,是一个BitmapDrawable。
后续文章待完成。
- transform的处理,缓存的细节。