Glide中有很多方面都是我们需要关注,比如生命周期的管理,缓存机制,设计模式等。其中生命周期的管理应该是最简单的,我今天就不进行介绍了,今天主要从数据加载流程中分析缓存机制和相关的设计模式
Glide可以加载的数据源非常多,比如File,网络,Drawable等,今天主要以网络图片为例进行介绍,其他的类型加载流程是一样的,如下:
Glide.with(this)
.load("https://img2.baidu.com/it/u=894463840,2154289921&fm=253&fmt=auto&app=138&f=JPEG?w=346&h=500")
.into(findViewById<ImageView>(R.id.meizi_iv))
目录
一、确定Glide从哪级缓存中获取图片资源
1.load方法
with方法我们就跳过了,这里主要做的就是生命周期管理的操作。我们直接进入load方法中查看:
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
这里有两个方法,我们先进入asDrawable中
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
进入as方法
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
as方法中创建了RequestBuilder对象,查看RequestBuilder的构造方法
protected RequestBuilder(
@NonNull Glide glide,
RequestManager requestManager,
Class<TranscodeType> transcodeClass,
Context context) {
this.glide = glide;
this.requestManager = requestManager;
this.transcodeClass = transcodeClass;
this.context = context;
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
this.glideContext = glide.getGlideContext();
initRequestListeners(requestManager.getDefaultRequestListeners());
apply(requestManager.getDefaultRequestOptions());
}
这里我们要特别关注的是第三个参数transcodeClass,这个参数是我们刚刚穿进去的Drawable.class。
我们返回load方法中,asDrawable返回的是RequestBuilder对象,所以.load方法时RequestBuilder类调用的,我们查看load方法
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
查看loadGeneric方法
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
这里我们记住的是RequestBuilder中的model参数,这个参数就是数据源参数,也就是String类型的。load方法到这里就结束了,刚刚提到的两个点:trancodeClass是Drawable.class,model为String类型的数据源
2.into方法
从上面我们直到了,这个into方法是在RequestBuilder中的,查看into方法源码
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView 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(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
switch方法体中判断了图片的scaletype,并且设置到了RequestOptions中,这个RequestOptions是RequestBuilder本身(这里也要关注一下,之后某些属性要在RequestOptions中查找)
调用了into的重载方法,其中第一个参数调用了glideContext的buildImageView方法,进入查看:
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
查看buildTarget方法,要注意第二个参数是我们上面提到的transcodeClass,也就是Drawable.class
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)");
}
}
根据条件判断,得出上面into方法中第一个参数类型就是DrawableImageViewTarget,我们继续查看上面调用的into重载方法
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
....
Request request = buildRequest(target, targetListener, options, callbackExecutor);
.....
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
篇幅有限,我留下了关键部分。第一个关键点是Request对象,第二个关键点是requestManager.track方法的调用。我们先看buildRequest方法
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
return buildRequestRecursive(
/*requestLock=*/ new Object(),
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
查看buildReuqestRecursive方法
private Request buildRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
...
Request mainRequest =
buildThumbnailRequestRecursive(
requestLock,
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
...
return errorRequestCoordinator;
}
buildThumbnailRequestRecursive方法
private Request buildThumbnailRequestRecursive(
Object requestLock,
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) {
...
return coordinator;
} else if (thumbSizeMultiplier != null) {
...
return coordinator;
} else {
// Base case: no thumbnail.
return obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
}
}
有两个判空:thumbnailBuilder和thumbSizeMultiplier,这个两个对象在没有调用设置的情况下为空,所以执行else条件,obtainRequest方法如下:
private Request obtainRequest(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
return SingleRequest.obtain(
context,
glideContext,
requestLock,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
从这里可以看出来,上面所说的Request对象就是SingleRequest。
我们回到into方法,查看第二个点requestManager.track
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
targetTracker主要就是生命周期变化时调用的,重点是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);
}
}
调用request的begin方法,request我们刚刚说到了,是SingleRequest,查看SingleRequest中的begin方法
@Override
public void begin() {
synchronized (requestLock) {
....
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(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
}
}
status初始化状态为PENDING,所以直接到第16行的if-else中的方法体。这里主要就是判断调用者是否有重写图片的宽高,没有的话会调用else中的方法,这里我们就不去追踪的,因为最后还会调到onSizeReady方法中。我们查看这个方法:
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
....
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);
...
}
}
engine类为Engine,调用了Engine的load方法(参数中requestOptions.getDiskCacheStrategy方法要注意,这个值递进查找可以知道是DiskCacheStrategy.AUTOMATIC),查看
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) {
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);
}
}
// Avoid calling back while holding the engine lock, doing so makes it easier for callers to
// deadlock.
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
}
有几个点我们关注一下:
(1)EngineKey:用此值在缓存中进行图片资源的查找
(2)loadFromMemory:从内存缓存中查找,我们暂时先不进去查看,因为是第一次加载,所以缓存中肯定是没有的。
所以会执行waitForExistingOrStartNewJob方法(参数中有个cb对象,这里我们要注意一下,从上面代码可知,cb对象为SingleRequest),进入查看:
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) {
....
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
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);
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
创建EngineJob和DecodeJob对象,decodeJob传入到了EngineJob的start方法中,查看start方法:
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
executor.execute(decodeJob);
}
其实就是线程池执行一个任务,具体的执行方法还是在decodeJob的run方法中,所以我们直接查看DecodeJob的run方法:
@Override
public void run() {
....
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
}
....
}
篇幅很多,但是关键的只有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);
}
}
runReason的初始值为INITIALIZE,所以先执行getNextStage方法,这个方法的作用就是将stage变化为下一个状态,查看getNextStage方法
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE
: getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE
: getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// Skip loading from source if the user opted to only retrieve the resource from cache.
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
刚刚我们说了,参数值是INITIALIZE,在判断条件中,调用了diskCacheStrategy.decodeCachedResource方法。上面我们已经知道了,diskCacheStrategy是DiskCacheStrategy.AUTOMATIC,所以我们查看它的decodeCachedResource方法,返回值固定为true。所以这里return的值为Stage.RESOURCE_CACHE
回到runWrapped方法中,继续执行getNextGenerator方法,这个方法的作用就是根据stage,来获取相应的Generator的对象
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);
}
}
刚刚说了,stage值为RESOURCE_CACHE,所以返回的类为ResourceCacheGenerator
返回到runWrapped方法中,所以currentGenerator为ResourceCacheGenerator(这个类我们要注意一下,它的作用是在内存缓存中查找图片资源),向下执行runGenerators方法
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
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();
}
}
while方法体重前两个判断都没有问题,第三个条件是调用currentGenerator的startNext,currentGenerator是ResourceCacheGenerator,所以我们进入它的startNext方法中
public boolean startNext() {
List<Key> sourceIds = helper.getCacheKeys();
if (sourceIds.isEmpty()) {
return false;
}
....
}
其实startNext的关键代码很多,那为什么我只贴了上面的代码呢?刚刚我说到了,ResourceCacheGenerator是在内存缓存中查找,这时候我们是第一次从网络上获取,所以缓存中肯定没有,sourceIds是空的,返回false,所以又回到了runGenerator方法的while中,此时三个条件成立,进入方法体中,继续执行getNextStage和getNextGenerator。代码就不贴了,上面已经有了。
第一步:stage值此时是RESOURCE_CACHE,并且diskCacheStrategy.decodeCacheData返回值固定为true,所以stage变为DATA_CACHE。
第二步:而在getNextGenerator方法中,根据stage,返回的值为DataCacheGenerator,之后在runGenerators的while方法体中,将currentGenerator赋值为DataCacheGenerator,这个值的作用就是在磁盘缓存中查找图片资源。
第三步:执行while中的第三个条件,也就是DataCacheGenerator中的startNext方法
@Override
public boolean startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if (sourceIdIndex >= cacheKeys.size()) {
return false;
}
.....
}
和ResourceCacheGenerator一样,第一次加载图片。但是此时cacheKeys中其实有了一条数据,不过循环之后,还是会return false跳出。再次回到DecodeJob的runGenerators方法体中,继续执行getNextStage和getNextGenerator方法。
(1)getNextStage中,当stage为DATA_CACHE时,会根据onlyRetrieveFromCache来判断,这个值是什么意思呢?翻译字面意思就是:只在缓存中进行查找,所以这个值肯定是false,stage变为SOURCE
(2)currentGenerator变为SourceGenerator,这个类的作用就是从原始地址获取图片资源
在while方法体中,当stage为SOURCE时,执行了DecodeJob中的reschedule方法,然后return了,所以while方法就结束了。我们进入reschedule中
@Override
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
首先,runReason变为SWITCH_TO_SOURCE_SERVICE;其次调用了callback.reschedule方法。这个callback是哪个类呢?其实就是EngineJob,我们在上面的Engine的方法waitForExistingOrStartNewJob中可以找到根据:decodeJob是由decodeJobFactory的build方法中创建的,最后一个参数就是callback,也就是EngineJob类,所以我们查看EngineJob的reschedule方法
@Override
public void reschedule(DecodeJob<?> job) {
getActiveSourceExecutor().execute(job);
}
其实还是线程池执行任务,也就是说,最后还是到了DecodeJob的run方法中,然后到了runWrapped方法中,上面已经说了这个流程了,在看一眼wrunWrapped方法
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);
}
}
刚刚说了,runReason变为了SWITCH_TO_SOURCE_SERVICE,所以继续执行runGenerators方法,方法就不再贴了,上面有。
此时的currentGenerator为SourceGenerator,所以执行它的startNext方法,至此就已经确定了,缓存中没有想要的图片资源,要在原始地址中获取。
二、从原始地址获取图片资源
上面说到了执行SourceGenerator的startNext方法,我们看一下
@Override
public boolean startNext() {
if (dataToCache != null) {
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;
startNextLoad(loadData);
}
}
return started;
}
(1)dataToCache表示要存储的缓存数据,此时原始数据还没有下载下来呢,更不用说缓存数据了,所以等于空
(2)sourceCacheGenerator就是上面说的DataCacheGenerator。作用先不说,这个对象暂时为空
(3)这里有一个loadData对象,类为LoadData,我们可以将这个LoadData理解为加载数据的包装类就可以了。
重点是在while方法,条件中,调用了hasNextModelLoader方法,进入查看(我们要在里面绕一大圈,所以要记住这里):
private boolean hasNextModelLoader() {
return loadDataListIndex < helper.getLoadData().size();
}
调用了helper的getLoadData方法,不用管helper是谁,点击去查看就行了
List<LoadData<?>> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
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;
}
这里有两个点要注意:(1)isLoadDataSet初始值为false(2)loadData是一个集合。
第5行,model这个对象我们在最上面提到过,是我们的图片网络地址,是String类型。glideContext.getRegistry对象为ModlLoaderRegistry,我们查看它的getModelLoaders方法
@NonNull
public <Model> List<ModelLoader<Model, ?>> getModelLoaders(@NonNull Model model) {
return modelLoaderRegistry.getModelLoaders(model);
}
查看getModelLoaders方法
public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
if (modelLoaders.isEmpty()) {
throw new NoModelLoaderAvailableException(model);
}
int size = modelLoaders.size();
boolean isEmpty = true;
List<ModelLoader<A, ?>> filteredLoaders = Collections.emptyList();
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0; i < size; i++) {
ModelLoader<A, ?> loader = modelLoaders.get(i);
if (loader.handles(model)) {
if (isEmpty) {
filteredLoaders = new ArrayList<>(size - i);
isEmpty = false;
}
filteredLoaders.add(loader);
}
}
if (filteredLoaders.isEmpty()) {
throw new NoModelLoaderAvailableException(model, modelLoaders);
}
return filteredLoaders;
}
先进入第2行的getModelLoadersForClass方法
@NonNull
private synchronized <A> List<ModelLoader<A, ?>> getModelLoadersForClass(
@NonNull Class<A> modelClass) {
List<ModelLoader<A, ?>> loaders = cache.get(modelClass);
if (loaders == null) {
loaders = Collections.unmodifiableList(multiModelLoaderFactory.build(modelClass));
cache.put(modelClass, loaders);
}
return loaders;
}
cache是做ModelLoader缓存的,不用理会。我们看multiModelLoaderFactory的build方法
@NonNull
synchronized <Model> List<ModelLoader<Model, ?>> build(@NonNull Class<Model> modelClass) {
try {
List<ModelLoader<Model, ?>> loaders = new ArrayList<>();
for (Entry<?, ?> entry : entries) {
if (alreadyUsedEntries.contains(entry)) {
continue;
}
if (entry.handles(modelClass)) {
alreadyUsedEntries.add(entry);
loaders.add(this.<Model, Object>build(entry));
alreadyUsedEntries.remove(entry);
}
}
return loaders;
} catch (Throwable t) {
alreadyUsedEntries.clear();
throw t;
}
}
这里有一个entries对象,是Entry的List。Entry这个类是什么呢?我们先看一下这个类:
private static class Entry<Model, Data> {
private final Class<Model> modelClass;
@Synthetic final Class<Data> dataClass;
@Synthetic final ModelLoaderFactory<? extends Model, ? extends Data> factory;
public Entry(
@NonNull Class<Model> modelClass,
@NonNull Class<Data> dataClass,
@NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory) {
this.modelClass = modelClass;
this.dataClass = dataClass;
this.factory = factory;
}
public boolean handles(@NonNull Class<?> modelClass, @NonNull Class<?> dataClass) {
return handles(modelClass) && this.dataClass.isAssignableFrom(dataClass);
}
public boolean handles(@NonNull Class<?> modelClass) {
return this.modelClass.isAssignableFrom(modelClass);
}
}
modelClass:就是我们数据源的类型,这里是String类型
dataClass:是要转换的类型,比如想将输入的网络地址(字符串类型),转换InputStream。
factory:创建ModelLoader的工厂类
这些数据是谁提供呢?我们要看Glide这个类的构造方法,我这里截个图,感兴趣的可以自己去找找看,Glide所支持的类型转另一种类型非常多
我们继续回到multiModelLoaderFactory的build方法中
(1)这个build方法作用到底是什么?其实就是想从系统提供的这些类型转换里找到可以对String类型进行转换的ModelLoader(我们暂时先不用管要转换成什么)。所以遍历了entries,然后调用了handles方法,参数为modelClass,目的就是刚刚说的,找到可以处理数据源为String类型的ModelLoader。
(2)找到对应的entry之后,又调用了MultiModelLoaderFactory的build方法,我们看一下这个方法
private <Model, Data> ModelLoader<Model, Data> build(@NonNull Entry<?, ?> entry) {
return (ModelLoader<Model, Data>) Preconditions.checkNotNull(entry.factory.build(this));
}
工厂类去构建对应的ModelLoader
到这里呢,我们就拿到了相应的ModelLoader,当然不是最终的,后续还需要进行筛选,选出来的数据如下(还有几个我没写,一眼就能看出不符合,这两个是我一开始分不清的情况)
modelClass | dataClass | ModelLoader | Factory |
String.class | InputStream.class | DataUrlLoader | DataUrlLoader.StreamFactory |
String.class | InputStream.class | StringLoader | StringLoader.StreamFactory |
拿到ModelLoader集合,我们回到ModelLoaderRegistry的getModelLoaders方法中,我再次提出来
public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
if (modelLoaders.isEmpty()) {
throw new NoModelLoaderAvailableException(model);
}
int size = modelLoaders.size();
boolean isEmpty = true;
List<ModelLoader<A, ?>> filteredLoaders = Collections.emptyList();
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0; i < size; i++) {
ModelLoader<A, ?> loader = modelLoaders.get(i);
if (loader.handles(model)) {
if (isEmpty) {
filteredLoaders = new ArrayList<>(size - i);
isEmpty = false;
}
filteredLoaders.add(loader);
}
}
if (filteredLoaders.isEmpty()) {
throw new NoModelLoaderAvailableException(model, modelLoaders);
}
return filteredLoaders;
}
这里的modelLoaders就是刚刚获取的ModelLoader的集合,我们可以看到,对这个集合进行了遍历,其中调用了loader.handles方法。第一个Loader是DataUrlLoader,所以我们先查看DataUrlLoader的handles方法,如下:
private static final String DATA_SCHEME_IMAGE = "data:image";
@Override
public boolean handles(@NonNull Model model) {
return model.toString().startsWith(DATA_SCHEME_IMAGE);
}
model是我们的网络图片地址,肯定不是以上面的字符串开头的,所以返回空。
第二个是StringLoader,我们查看它的handles方法,
@Override
public boolean handles(@NonNull String model) {
// Avoid parsing the Uri twice and simply return null from buildLoadData if we don't handle this
// particular Uri type.
return true;
}
固定返回true。
所以经过筛选后,只剩下一个符合的ModelLoader,那就是StringModel。
我们再次回到DecodeHelper的getLoadData方法,我在贴出来
List<LoadData<?>> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
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;
}
对这个ModelLoader集合进行遍历,然后调用ModelLoader的buildLoadData方法,集合中只有一个值,那就是StringLoader,查看StringLoader的buildLoadData
private final ModelLoader<Uri, Data> uriLoader;
// Public API.
@SuppressWarnings("WeakerAccess")
public StringLoader(ModelLoader<Uri, Data> uriLoader) {
this.uriLoader = uriLoader;
}
@Override
public LoadData<Data> buildLoadData(
@NonNull String model, int width, int height, @NonNull Options options) {
Uri uri = parseUri(model);
if (uri == null || !uriLoader.handles(uri)) {
return null;
}
return uriLoader.buildLoadData(uri, width, height, options);
}
我们发现,这类是ModelLoader,里面有一个参数uriLoader也是ModelLoader,并且StringLoader的buildLoadData的返回值,其实就是uriLoader的buildLoadData的返回值。我们仔细观察一下上面的buildLoadData方法,发现model(我们的数据源,也就是网络地址)转换为了Uri。也就是说数据源变成了Uri,所以处理数据源的类也就是变成了上面的uriLoader,uriLoader是从StringLoader的构造器中传进来的,我们看一下这个构造方法在哪里调用的,如图:
三个地方调用,但是很明显,肯定是一个调用的地方,第二个和第三个是和File有关的。我们点进去递进查找,发现找到了MultiModelLoaderFactory的build方法,但是这个build不是上面说的build方法,这里的build参数多了一个输出类型的判断,并且返回值为ModelLoader,而不是ModelLoader的集合。在entries中查找输入类型为Uri.class,输入类型为InputStream.class的ModelLoader。找到的结果只有一个,如下
modelClass | dataClass | ModelLoader | Factory |
Uri.class | InputStream.class | HttpUriLoader | HttpUriLoader.Factory |
所以从StringLoader的buildLoadData方法中,再跳到HttpUriLoader的buildLoadData方法中
private final ModelLoader<GlideUrl, InputStream> urlLoader;
// Public API.
@SuppressWarnings("WeakerAccess")
public HttpUriLoader(ModelLoader<GlideUrl, InputStream> urlLoader) {
this.urlLoader = urlLoader;
}
@Override
public LoadData<InputStream> buildLoadData(
@NonNull Uri model, int width, int height, @NonNull Options options) {
return urlLoader.buildLoadData(new GlideUrl(model.toString()), width, height, options);
}
和StringLoader很像,所以我们需要知道urlLoader是谁,同样的,我们查看在哪里调用了HttpUriLoader的构造方法,只有一个地方,就是在HttpUriLoader.Factory的build中,
public ModelLoader<Uri, InputStream> build(MultiModelLoaderFactory multiFactory) {
return new HttpUriLoader(multiFactory.build(GlideUrl.class, InputStream.class));
}
这里千万别糊涂,这里的build在获取ModelLoader的时候调用过了,对不对。
很不幸,这里的ModelLoader并没有明确表达,依然在multiModelLoaderFactory的build方法中去查找,输入类型为GlideUrl,输出类型为InputStream,结果只有一个,如下
modelClass | dataClass | ModelLoader | Factory |
GlideUrl.class | InputStream.class | HttpGlideUrlLoader | HttpGlideUrlLoader.Factory |
所以呢,HttpUriLoader中的urlLoader是HttpGlideUrlLoader。我们再次从HttpUriLoader的buildLoadData跳转到HttpGlideUrlLoader的buildLoadData方法中,如下:
@Override
public LoadData<InputStream> buildLoadData(
@NonNull GlideUrl model, int width, int height, @NonNull Options options) {
// GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time
// spent parsing urls.
GlideUrl url = model;
if (modelCache != null) {
url = modelCache.get(model, 0, 0);
if (url == null) {
modelCache.put(model, 0, 0, model);
url = model;
}
}
int timeout = options.get(TIMEOUT);
return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}
山路十八弯,终于走出了第一个十八弯。找到了最终的LoadData,第二个参数是我们要关注的:HttpUrlFetcher,带有Fetcher的类都是实际进行数据获取的类,这里HttpUrlFetcher就是下载图片的核心类。
找到之后,我们就向上进行返回,回到了DecodeHelper的getLoadData方法,我再贴一下代码:
List<LoadData<?>> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
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;
}
从上面的流程,我们直到,loadData中有两个数据。到这里,大家千万别忘了,getLoadData方法的调用是在SourceGenerator的hasNextModelLoader方法,而hasNextModelLoader方法的调用是在startNext方法中,我再贴一下startNext方法,帮大家回忆一下
@Override
public boolean startNext() {
if (dataToCache != null) {
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;
startNextLoad(loadData);
}
}
return started;
}
OKOK,第二个十八弯也出来了。hasNextModelLoader返回值为true,这个我们刚刚的结论,对吧。
(1)第17行,从我们刚刚获取的LoadData集合中获取第一个loadData
(2)started变为true,然后执行startNextLoad方法
private void startNextLoad(final LoadData<?> toStart) {
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);
}
}
});
}
就是执行fetcher的loadData方法,fetcher我们上面提到了,是HttpUrlFetcher,我们查看一下:
@Override
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data for url", e);
}
callback.onLoadFailed(e);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
}
}
}
(1)loadDataWithRedirects方法就是进行网络访问,获取图片数据
(2)callback.onDataReady就是将结果返回给上一层
至此,网络图片数据的获取就结束了
三、将获取的数据进行缓存
数据是获取了,但是还没有进行数据缓存的操作,我们继续从SourceGenerator的startNextLoad中进行
private void startNextLoad(final LoadData<?> toStart) {
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);
}
}
});
}
onDataReady是数据获取之后的回调方法,data类型为InputStream.class,执行onDataReadyInternal方法
@SuppressWarnings("WeakerAccess")
@Synthetic
void onDataReadyInternal(LoadData<?> loadData, Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
cb.reschedule();
} else {
cb.onDataFetcherReady(
loadData.sourceKey,
data,
loadData.fetcher,
loadData.fetcher.getDataSource(),
originalKey);
}
}
首先data肯定不是空的,然后判断diskCacheStrategy.isDataCacheable返回值
(1)diskCacheStrategy我们上面说了,是DiskCacheStrategy.AUTOMATIC。
(2)loadData.fetcher是HttpUrlFetcher,getDataSource返回值固定为DataSource.REMOTE
查看isDataCacheable方法
@Override
public boolean isDataCacheable(DataSource dataSource) {
return dataSource == DataSource.REMOTE;
}
很明显,就是true。所以在onDataReadyInternal方法中,执行if中的操作
(1)dataToCache赋值为data,这是要缓存的类对象
(2)调用cb.reschedule,这个cb我们没有关注过,我们进行调用查找,很明显就能直到,cb其实就是DecodeJob
查看DecodeJob的reschedule方法
@Override
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
希望大家没有忘记这里,我们之前也调用到了这里,callback为EngineJob,在EngineJob的reschedule方法中,使用线程池执行了DecodeJob的run方法(没印象的小伙伴可以向上翻翻),所以我们又再次回到了DecodeJob的run方法中,然后是runWrapped方法,直接看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);
}
}
runReason为SWITCH_TO_SOURCE_SERVICE,所以执行runGenerators方法:
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
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.
}
不废话,直接进入SourceGenerator的startNext方法中
@Override
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
....
}
虽然又到了startNext,但是有了不一样的地方,dataToCache不为空了,所以执行cacheData方法。
private void cacheData(Object dataToCache) {
long startTime = LogTime.getLogTime();
try {
Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
DataCacheWriter<Object> writer =
new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
helper.getDiskCache().put(originalKey, writer);
....
} finally {
loadData.fetcher.cleanup();
}
sourceCacheGenerator =
new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
}
(1)这里要是深究起来,也会比较复杂,我们只要直到一件事就可以了,将资源写入到了磁盘缓存中。第8行的位置,getDiskCache获取的就是磁盘缓存的容器,然后进行了put操作
(2)sourceCacheGenerator赋值为DataCacheGenerator,第一个参数我们要关注,是资源的key,传入到了DataCacheGenerator中。
至此,数据被缓存到了磁盘中
四、将数据加入到内存缓存,并且展示到ImageView中
我们回到上面SourceGenerator的startNext方法
@Override
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
....
}
此时sourceCacheGenerator为DataCacheGenerator,不为空,然后执行了startNext方法,我们查看startNext方法
@Override
public boolean startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if (sourceIdIndex >= cacheKeys.size()) {
return false;
}
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;
}
(1)根据缓存的key,从磁盘缓存中拿到了刚刚存入的缓存文件,也就是cacheFile
(2)调用了helper的getModelLoaders方法,获取了modelLoader的列表,看一下getModelLoaders的方法
List<ModelLoader<File, ?>> getModelLoaders(File file)
throws Registry.NoModelLoaderAvailableException {
return glideContext.getRegistry().getModelLoaders(file);
}
根据file获取ModelLoader。这里大家应该很眼熟了把。在SourceGenerator的流程中,有过相似的代码,流程都是一样的,所以我就不再进去寻找了,结果如下:
modelClass | dataClass | ModelLoader | Factory | Fetcher |
File.class | ByteBuffer.class | ByteBufferFileLoader | ByteBufferFileLoader.Factory | ByteBufferFetcher |
File.class | InputStream.class | FileLoader | FileLoader.StreamFactory | FileFetcher |
(1)之后进入startNext的第二个while,其中获取了第一个ModelLoader,也就是ByteBufferFileLoader,构建了loadData。loadData中的Fetcher我已经在上面贴出来了,是ByteBufferFetcher
(2)ByteBufferFetcher对象调用了loadData,进行了数据的获取
我们直接进入ByteBufferFetcher的loadData方法中查看
@Override
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super ByteBuffer> callback) {
ByteBuffer result;
try {
result = ByteBufferUtil.fromFile(file);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to obtain ByteBuffer for file", e);
}
callback.onLoadFailed(e);
return;
}
callback.onDataReady(result);
}
result对象类型为ByteBuffer,通过callback的onDataReady方法回到了DataCacheGenerator中,我们看一下
@Override
public void onDataReady(Object data) {
cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
}
很眼熟的代码,我们上面说过,具体的流程我不再赘述,我直接描述一下:
cb是SourceGenerator
SourceGenerator.onDataFetcherReady=>DecodeJob.onDataFetcherReady,我直接看DecodeJob的onDataFetcherReady方法
@Override
public void onDataFetcherReady(
Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;
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();
}
}
}
这里的线程没有变化,所以执行decodeFromRetrievedData方法,我们查看一下
private void decodeFromRetrievedData() {
Resource<R> resource = null;
try {
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
第4行,调用了decodeFromData方法,这里又是一波十八弯,实在是弯不动了,我就口述一下吧。
我们从上面的流程知道了,currentData是ByteBuffer类型的,但是我们想在ImageView上展示出来的类型是Drawable(在最一开始说过,transcodeClass类型),所以现将ByteBuffer编码为Bitmap类型,然后再将Bitmap转码为BitmapDrawable。
再次调用notifyEncodeAndRelease方法,进去看看:
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
if (resource instanceof Initializable) {
((Initializable) resource).initialize();
}
Resource<R> result = resource;
LockedResource<R> lockedResource = null;
if (deferredEncodeManager.hasResourceToEncode()) {
lockedResource = LockedResource.obtain(resource);
result = lockedResource;
}
notifyComplete(result, dataSource);
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();
}
调用notifyComplete方法
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
callback.onResourceReady(resource, dataSource);
}
这个callback对象,上面提过,是EngineJob,所以查看EngineJob的onResourceReady方法
@Override
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
synchronized (this) {
this.resource = resource;
this.dataSource = dataSource;
}
notifyCallbacksOfResult();
}
查看notifyCallbacksOfResult方法
void notifyCallbacksOfResult() {
....
engineJobListener.onEngineJobComplete(this, localKey, localResource);
for (final ResourceCallbackAndExecutor entry : copy) {
entry.executor.execute(new CallResourceReady(entry.cb));
}
decrementPendingCallbacks();
}
(1)第3行:将数据存到内存缓存中的活动缓存,感兴趣的同学可以点击去看一下
(2)for循环中的,线程池执行了一个任务,所以我们直接进入CallResourceReady中的run方法查看:
@Override
public void run() {
// Make sure we always acquire the request lock, then the EngineJob lock to avoid deadlock
// (b/136032534).
synchronized (cb.getLock()) {
synchronized (EngineJob.this) {
if (cbs.contains(cb)) {
// Acquire for this particular callback.
engineResource.acquire();
callCallbackOnResourceReady(cb);
removeCallback(cb);
}
decrementPendingCallbacks();
}
}
}
查看callCallbackOnResourceReady方法
void callCallbackOnResourceReady(ResourceCallback cb) {
try {
cb.onResourceReady(engineResource, dataSource);
} catch (Throwable t) {
throw new CallbackException(t);
}
}
cb其实是SingleRequest,我们直接进入SingleRequest的onResourceReady方法查看:
public void onResourceReady(Resource<?> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
Resource<?> toRelease = null;
try {
....
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
} finally {
if (toRelease != null) {
engine.release(toRelease);
}
}
}
查看onResourceReady方法
private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
....
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
我们终于看见了target,这个target就是对我们ImageView的一个封装,之后我们就不继续了,无非就是数据设置之类的操作。
五、总结
写了4万字,估计没人看,就当自己的笔记了,我还是总结一下看源码的方法
1.多做笔记
像Glide这种调用栈比较深,比较乱的,我们再看的时候一定要做随手笔记,防止我们看的比较深的时候,会忘记之前的参数是什么类型,什么意思
2.Debug调试
三方可以使用Debug调试的,我们看的时候总是有不确定的时候,Debug一下,看看到底是不是代码走到了这里,参数具体是什么类型
3.反向查找
思路断了的时候,反向查找的效果会比较好。比如:我在看的时候,没有找到数据是怎么放到内存缓存的,这时候可以使用反向查找,看看内存缓存在哪里添加,和自己所看的流程重合了,就OK了
4.多看
源码还是要多看,反复咀嚼