前言
前面一章我们介绍了Glide 下载图片的过程,我们本章梳理下载图片之后回调的过程
一、回调
loadData 获取到数据流之后通知回调,数据就绪。
此处的callbakc 实际指向的是SourceGenerator。
所以看看SourceGenerator对象的onDataReady方法都做了什么
private final FetcherReadyCallback cb; //成员变量
@Override
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(
loadData.fetcher.getDataSource())) {
//需要缓存到磁盘
//保存网络图片输入流到dataToCache
dataToCache = data;
//重新规划图片加载
cb.reschedule();
} else {
//不需要缓存到磁盘
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
一般情况下默认是缓存到磁盘的,所有我们看cb.reschedule的源码,这个cb 是FetcherReadyCallback 对象,它实际指向的是DecodeJob。
DecodeJob
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
这里的callback 实际是EngineJob
接着又进入了DecodeJob的run方法,根据上一篇对DecodeJob run方法的分析,它会进入runWrapped的SWITCH_TO_SOURCE_SERVICE分支,SWITCH_TO_SOURCE_SERVICE分支直接调用runGenerators,而当前的图片执行器还是网络执行器SourceGenerator,接着又执行SourceGenerator的startNext方法:
public boolean startNext() {
if (dataToCache != null) {
//dataToCache就是网络请求的网络图片输入流,此时已经不是null 了
Object data = dataToCache;
dataToCache = null;
//缓存网络图片输入流到磁盘中
cacheData(data);
}
//执行原始图片磁盘缓存输入流执行器
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
//...
}
绕了一大圈又回到SourceGenerator的startNext,在startNext中调用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());
//创建原始图片缓存key
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);
}
具体怎么缓存的大家参考下面这篇文章[Glide缓存](https://www.jianshu.com/p/3612a96459ec)
当DataCacheGenerator缓存玩图片之后会调用SourceGenerator的onDataFetcherReady
```java
@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
cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
}
上面说过此处的cb 实际是DecodeJob
```java
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;
//将数据交给DecodeJob的currentData持有
this.currentData = data;
this.currentFetcher = fetcher;
this.currentDataSource = dataSource;
this.currentAttemptingKey = attemptedKey;
if (Thread.currentThread() != currentThread) {
//修改runReason
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
TraceCompat.beginSection("DecodeJob.decodeFromRetrievedData");
try {
//省略部分代码
decodeFromRetrievedData();
} finally {
TraceCompat.endSection();
}
}
callback.reschedule(this) 会开启一个新的线程进入runWrapper 进而调用decodeFromRetrievedData,大家可以结合上一篇文章一起看,我们这里直接分析decodeFromRetrievedData 方法。
private void decodeFromRetrievedData() {
Resource<R> resource = null;
try {
//1、将Inpustream转换成Resource对象
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
//2、将数据继续传递
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
上面的方法做了两件事:
1、将图片数据InputStream流转换成Resource对象
2、调用notifyEncodeAndRelease将数据继续传递。
此时我们的图片数据由InputStream转换成了Resource对象。接下来分析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();
}
}
onEncodeComplete();
}
我们来到了DecodeJob类的notifyComplete方法:
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
//又是callback
callback.onResourceReady(resource, dataSource);
}
notifyComplete方法中我们见到了又一个callback,并且调用其onResourceReady方法,这个callback 实际指向的是EngineJob,所以看看EngineJob的onResourceReady方法:
@Override
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
//原始数据
this.resource = resource;
this.dataSource = dataSource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
finally,见到了Handler的身影,说明我们距离终点不远了,上文的handler发送了MSG_COMPLETE消息该handler来处理,
public boolean handleMessage(Message message) {
EngineJob<?> job = (EngineJob<?>) message.obj;
switch (message.what) {
case MSG_COMPLETE:
job.handleResultOnMainThread();
仅仅是调用了EngineJob的handleResultOnMainThread方法,此时我们已经将图片数据传递到了UI线程:
@Synthetic
void handleResultOnMainThread() {
//将数据转换成engineResource
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
engineResource.acquire();
listener.onEngineJobComplete(this, key, engineResource);
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = cbs.size(); i < size; i++) {
ResourceCallback cb = cbs.get(i);
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
//又是一个callback
cb.onResourceReady(engineResource, dataSource);
}
}
// Our request is complete, so we can release the resource.
engineResource.release();
release(false /*isRemovedFromQueue*/);
}
该方法做了两件事:
1、将resource赋值给engineResource
2、调用callback
此处的callback 是ResourceCallback,实际指向的是SingleRequest
所以我们进入该SingleReqeust的onResourceReady方法:
@Override
public void onResourceReady(Resource<?> resource, DataSource dataSource) {
//省略部分逻辑
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
*
private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
isCallingCallbacks = true;
try {
if ((requestListener == null
|| !requestListener.onResourceReady(result, model, target,
dataSource, isFirstResource))
&& (targetListener == null
|| !targetListener.onResourceReady(result, model, target, dataSource, isFirstResource))) {
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
//最终调用target的onResourceReady
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
此处的target就是DrawableImageViewTarget,该target的onResourceReady方法的最总逻辑就是调用:
imageView.setImageDrawable(resource);
来完成图片的展示。
到此为止,本篇分析完毕,分析源码的过程中四个callback来回调度可把我绕坏了。
总结
至此,关于Glide 下载完图片之后缓存图片与回调显示图片的过程就梳理完了。虽然过程梳理完了,但是别人为什么这么写,为什么这么架构,还需要细细品味。