Glide 源码阅读笔记(五)
在第一篇文章中我简单介绍了 Glide
实例的创建过程,重点介绍了 Glide
的内存缓存实现和磁盘的缓存实现:Glide 源码阅读笔记(一)
在第二篇文章中介绍了 Glide
对生命周期的管理: Glide 源码阅读笔记(二)
在第三篇文章中介绍了 Request
和 RequestCoordinator
,还简单介绍了 Registry
中的核心组件:Glide 源码阅读笔记(三)
第四篇文章中介绍了 Glide
如何加载内存缓存和磁盘缓存的资源。其中内存缓存又分为存活的内存缓存资源和被缓存的内存缓存资源;磁盘缓存分为 RESOURCE_CACHE
类型(有尺寸等参数作为 key
)缓存与 DATA_CACHE
类型(从网络中加载的原始缓存数据,无尺寸等等信息):Glide 源码阅读笔记(四)
本篇文章继续接着上篇文章中介绍没有磁盘缓存和内存缓存时,如何加载网络中的数据,以及如何写入 RESOURCE_CACHE
与 DATA_CACHE
磁盘缓存。另外再讲讲加载任务对 Android
中生命周期的响应。
加载网络数据和写入磁盘缓存
在前面的文章中介绍过加载缓存时会工作在 DiskCacheExecutor
中执行(也就是 ResourceCacheGenerator
和 DataCacheGenerator
),而加载网络数据时会在 ActiveSourceExecutor
中执行(SourceGenerator
)。所以我们就以 SourceGenerator#startNext()
方法开始分析:
Java
@Override
public boolean startNext() {
// ...
while (!started && hasNextModelLoader()) {
// 找到一个可用的 DataLoader 中的 LoadData 对象
loadData = helper.getLoadData().get(loadDataListIndex++);
// 然后通过 LoadData 中最后的输出对象的 Class 对象,然后去查找 Decoder 和 Transcoder,他们都被封装在 LoadPath 中。
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
// 找到可以用的 LoadPath 对象。
startNextLoad(loadData);
}
}
return started;
}
我删除了部分本次逻辑不会用到的代码,后面再继续看。这里首先去查找可以用的 DataLoader
,然后获取到它的 LoadData
对象,然后获取到最后它处理后的对象的 Class
对象。我们这里其实就是找到一个网络请求相关的 DataLoader
,我们输入的对象是 String
类型的地址,然后它的返回对象就是一个 InputStream
。
然后继续查找能够处理 InputStream
的 Decoder
与 Transcoder
,然后他们被封装在 LoadPath
对象中,然后调用 startNextLoad()
方法:
Java
private void startNextLoad(final LoadData<?> toStart) {
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback<Object>() {
@Override
public void onDataReady(@Nullable Object data) {
// 回调 LoadData 加载网络数据成功。
if (isCurrentRequest(toStart)) {
onDataReadyInternal(toStart, data);
}
}
@Override
public void onLoadFailed(@NonNull Exception e) {
if (isCurrentRequest(toStart)) {
onLoadFailedInternal(toStart, e);
}
}
});
}
就是一个简单的异步回调,成功后会调用 onDataReadyInternal()
方法,其实这个 data
就是 InputStream
。
Java
@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);
}
}
上面的代码分为两种情况,一种是允许 DataCache
,一种是不允许,我们直接看允许缓存的逻辑(不允许缓存更加简单)。它会把 data
保存在 dataToCache
变量中,然后调用 cb
的 reschedule()
方法,这个 cb
其实就是 DecodeJob
,这个方法它会再次触发 SourceGenerator#startNext()
方法,这个时候我们就能继续看之前我们删除掉的那部分代码了:
Java
@Override
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
try {
// 执行缓存 DataCache 操作。
boolean isDataInCache = cacheData(data);
if (!isDataInCache) {
return true;
}
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to properly rewind or write data to cache", e);
}
}
}
// 缓存成功后会调用 DataCacheGenerator#startNext() 方法
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
// ...
return started;
}
由于回调成功后 dataToCache
变量就不为空了,然后通过 cacheData()
方法来缓存 DataCache
到本地磁盘。如果缓存成功,会创建一个 DataCacheGenerator
(它是和 DecodeJob
中的 DataCacheGenerator
是不同的实例),然后调用其 startNext()
方法,简单来说就是缓存成功后再去从缓存中再去加载一次,然后继续后续的操作。
我们再来看看 cacheData()
方法的实现:
Java
private boolean cacheData(Object dataToCache) throws IOException {
long startTime = LogTime.getLogTime();
boolean isLoadingFromSourceData = false;
try {
// 用 DataRewinder 来封装对应的 data,使其可以重复的读(也就是让 InputStream 可以重复的读)
DataRewinder<Object> rewinder = helper.getRewinder(dataToCache);
// 重置 data。
Object data = rewinder.rewindAndGet();
// 查找对应的 Encoder
Encoder<Object> encoder = helper.getSourceEncoder(data);
// 构建用于写入文件缓存的 DataCacheWriter 对象。
DataCacheWriter<Object> writer = new DataCacheWriter<>(encoder, data, helper.getOptions());
// 构建用于缓存的 DataCacheKey
DataCacheKey newOriginalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
DiskCache diskCache = helper.getDiskCache();
// 写入缓存
diskCache.put(newOriginalKey, writer);
// 写入后,判断是否已经写入成功
if (diskCache.get(newOriginalKey) != null) {
// 写入成功后构建一个 DataCacheGenerator 对象
originalKey = newOriginalKey;
sourceCacheGenerator =
new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
// We were able to write the data to cache.
return true;
} else {
isLoadingFromSourceData = true;
// 如果缓存写入失败,就直接回调 DecodeJob。
cb.onDataFetcherReady(
loadData.sourceKey,
rewinder.rewindAndGet(),
loadData.fetcher,
loadData.fetcher.getDataSource(),
loadData.sourceKey);
}
// We failed to write the data to cache.
return false;
} finally {
if (!isLoadingFromSourceData) {
loadData.fetcher.cleanup();
}
}
}
上面代码的注释我写的很清楚了,就不再赘述了,如果写入本地缓存成功,会创建 DataCacheGenerator
,前面我们说到会调用它的 startNext()
方法,也就是会触发 DataCacheGenerator
去加载刚才写入的缓存,DataCacheGenerator
我在上篇文章中已经介绍过了,不知道的同学翻翻前面的文章。
加载成功后会调用 SourceGenerator#onDataFetcherReady()
方法:
Java
@Override
public void onDataFetcherReady(
Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
}
然后继续回调 DecodeJob#onDataFetcherReady()
方法:
Java
@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;
this.isLoadingFromAlternateCacheKey = sourceKey != decodeHelper.getCacheKeys().get(0);
if (Thread.currentThread() != currentThread) {
reschedule(RunReason.DECODE_DATA);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
上面的方法处理也非常简单将回调的各种数据保存在成员变量中,我们这里没有切线程,所以接着调用 decodeFromRetrievedData()
。
Java
private void decodeFromRetrievedData() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey(
"Retrieved data",
startFetchTime,
"data: "
+ currentData
+ ", cache key: "
+ currentSourceKey
+ ", fetcher: "
+ currentFetcher);
}
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, isLoadingFromAlternateCacheKey);
} else {
runGenerators();
}
}
通过调用 decodeFromData()
方法来完成解码,解码成功后调用 notifyEncodeAndRelease()
方法。
Java
private <Data> Resource<R> decodeFromData(
DataFetcher<?> fetcher, Data data, DataSource dataSource) throws GlideException {
try {
if (data == null) {
return null;
}
long startTime = LogTime.getLogTime();
Resource<R> result = decodeFromFetcher(data, dataSource);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded result " + result, startTime);
}
return result;
} finally {
fetcher.cleanup();
}
}
继续调用 decodeFromFetcher()
方法。
Java
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
throws GlideException {
LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
return runLoadPath(data, dataSource, path);
}
获取到对应的 LoadPath
,然后继续调用 runLoadPath()
方法。
Java
private <Data, ResourceType> Resource<R> runLoadPath(
Data data, DataSource dataSource, LoadPath<Data, ResourceType, R> path)
throws GlideException {
Options options = getOptionsWithHardwareConfig(dataSource);
DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
try {
return path.load(
rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
} finally {
rewinder.cleanup();
}
}
这里继续调用 LoadPath#load()
来完成解码。这里其实有两个过程,一个是 Decoder
的解码过程,然后是 Transcoder
将 Decoder
的结果转换成 Target
能够渲染的类型。其中 DecodeCallback
能够拦截处理 Decoder
返回的结果。
Java
@NonNull
@Override
public Resource<Z> onResourceDecoded(@NonNull Resource<Z> decoded) {
return DecodeJob.this.onResourceDecoded(dataSource, decoded);
}
我们看到又调用了 DecodeJob#onResourceDecoded()
方法。这个方法里面就要来处理 RESOURCE_DISK_CACHE
了。
Java
@Synthetic
@NonNull
<Z> Resource<Z> onResourceDecoded(DataSource dataSource, @NonNull Resource<Z> decoded) {
@SuppressWarnings("unchecked")
Class<Z> resourceSubClass = (Class<Z>) decoded.get().getClass();
Transformation<Z> appliedTransformation = null;
Resource<Z> transformed = decoded;
if (dataSource != DataSource.RESOURCE_DISK_CACHE) {
// 通过 Transformation 对尺寸和 ScaleType 的处理。
appliedTransformation = decodeHelper.getTransformation(resourceSubClass);
transformed = appliedTransformation.transform(glideContext, decoded, width, height);
}
// TODO: Make this the responsibility of the Transformation.
if (!decoded.equals(transformed)) {
decoded.recycle();
}
final EncodeStrategy encodeStrategy;
final ResourceEncoder<Z> encoder;
// 判断是否允许 Resource Encoder
if (decodeHelper.isResourceEncoderAvailable(transformed)) {
// 查找对应的 Encoder
encoder = decodeHelper.getResultEncoder(transformed);
// 获取对应的 EncodeStrategy
encodeStrategy = encoder.getEncodeStrategy(options);
} else {
encoder = null;
encodeStrategy = EncodeStrategy.NONE;
}
Resource<Z> result = transformed;
boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey);
// 判断是否允许 Resource Cache.
if (diskCacheStrategy.isResourceCacheable(
isFromAlternateCacheKey, dataSource, encodeStrategy)) {
if (encoder == null) {
throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass());
}
final Key key;
// 根据 EncodeStrategy 来选择不同的缓存 Key
switch (encodeStrategy) {
case SOURCE:
key = new DataCacheKey(currentSourceKey, signature);
break;
case TRANSFORMED:
key =
new ResourceCacheKey(
decodeHelper.getArrayPool(),
currentSourceKey,
signature,
width,
height,
appliedTransformation,
resourceSubClass,
options);
break;
default:
throw new IllegalArgumentException("Unknown strategy: " + encodeStrategy);
}
LockedResource<Z> lockedResult = LockedResource.obtain(transformed);
// 初始化 deferredEncodeManager。
deferredEncodeManager.init(key, encoder, lockedResult);
result = lockedResult;
}
return result;
}
上面有一个点需要注意就是如果数据来源是 RESOURCE_DISK_CACHE
那么就不需要裁剪操作,因为 RESOURCE_DISK_CACHE
缓存中的数据已经做过裁剪操作了。如果需要处理 RESOURCE_DISK_CACHE
那么就会初始化 deferredEncodeManager
。
我们再来看看解码完成后 notifyEncodeAndRelease()
方法是怎么处理的:
Java
private void notifyEncodeAndRelease(
Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
GlideTrace.beginSection("DecodeJob.notifyEncodeAndRelease");
try {
// ...
try {
if (deferredEncodeManager.hasResourceToEncode()) {
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
if (lockedResource != null) {
lockedResource.unlock();
}
}
// ...
} finally {
GlideTrace.endSection();
}
}
我们看到它会调用 DeferredEncodeManager#encode()
方法:
Java
void encode(DiskCacheProvider diskCacheProvider, Options options) {
GlideTrace.beginSection("DecodeJob.encode");
try {
diskCacheProvider
.getDiskCache()
.put(key, new DataCacheWriter<>(encoder, toEncode, options));
} finally {
toEncode.unlock();
GlideTrace.endSection();
}
}
也没什么好说的了,直接就写入到磁盘缓存中了。
我们再看看缓存策略的接口:
Java
// 是否可以写入 DataCache 缓存
public abstract boolean isDataCacheable(DataSource dataSource);
// 是否可以写入 ResourceCache 缓存
public abstract boolean isResourceCacheable(
boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy);
// 是否可以读取 ResourceCache 缓存
public abstract boolean decodeCachedResource();
// 是否可以读取 DataCache 缓存
public abstract boolean decodeCachedData();
Glide
实现了以下几种:
AUTOMATIC
(默认策略)
Java
public static final DiskCacheStrategy AUTOMATIC =
new DiskCacheStrategy() {
@Override
public boolean isDataCacheable(DataSource dataSource) {
return dataSource == DataSource.REMOTE;
}
@Override
public boolean isResourceCacheable(
boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
return ((isFromAlternateCacheKey && dataSource == DataSource.DATA_DISK_CACHE)
|| dataSource == DataSource.LOCAL)
&& encodeStrategy == EncodeStrategy.TRANSFORMED;
}
@Override
public boolean decodeCachedResource() {
return true;
}
@Override
public boolean decodeCachedData() {
return true;
}
};
ALL
Java
public static final DiskCacheStrategy ALL =
new DiskCacheStrategy() {
@Override
public boolean isDataCacheable(DataSource dataSource) {
return dataSource == DataSource.REMOTE;
}
@Override
public boolean isResourceCacheable(
boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
return dataSource != DataSource.RESOURCE_DISK_CACHE
&& dataSource != DataSource.MEMORY_CACHE;
}
@Override
public boolean decodeCachedResource() {
return true;
}
@Override
public boolean decodeCachedData() {
return true;
}
};
NONE
Java
public static final DiskCacheStrategy NONE =
new DiskCacheStrategy() {
@Override
public boolean isDataCacheable(DataSource dataSource) {
return false;
}
@Override
public boolean isResourceCacheable(
boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
return false;
}
@Override
public boolean decodeCachedResource() {
return false;
}
@Override
public boolean decodeCachedData() {
return false;
}
};
DATA
Java
public static final DiskCacheStrategy DATA =
new DiskCacheStrategy() {
@Override
public boolean isDataCacheable(DataSource dataSource) {
return dataSource != DataSource.DATA_DISK_CACHE && dataSource != DataSource.MEMORY_CACHE;
}
@Override
public boolean isResourceCacheable(
boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
return false;
}
@Override
public boolean decodeCachedResource() {
return false;
}
@Override
public boolean decodeCachedData() {
return true;
}
};
RESOURCE
Java
public static final DiskCacheStrategy RESOURCE =
new DiskCacheStrategy() {
@Override
public boolean isDataCacheable(DataSource dataSource) {
return false;
}
@Override
public boolean isResourceCacheable(
boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
return dataSource != DataSource.RESOURCE_DISK_CACHE
&& dataSource != DataSource.MEMORY_CACHE;
}
@Override
public boolean decodeCachedResource() {
return true;
}
@Override
public boolean decodeCachedData() {
return false;
}
};
生命周期对 Request 的影响
在第二篇文章中我介绍了 Glide
对 Android
生命周期的处理,Glide
会监听 FramgentActivity
和 Fragment
的 onStart()
,onStop()
和 onDestroy()
三个生命周期。这些生命周期时间会下发至 RequestManager
,然后 RequestManager
再去控制它的 Request
。
onStart()
在 onStart()
生命周期中主要是重新开始 onStop()
生命周期中被暂停的 Request
。我们直接看看 RequestManager#onStart()
方法源码:
Java
@Override
public synchronized void onStart() {
// 恢复暂停的 Request。
resumeRequests();
// 回调 Target 的 onStart() 方法。
targetTracker.onStart();
}
我们首先看看 resumeRequests()
方法中是如何暂停 Request
的:
Java
public synchronized void resumeRequests() {
requestTracker.resumeRequests();
}
继续追踪 RequestTracker#resumeRequests()
方法的实现:
Java
public void resumeRequests() {
// 更新暂停状态
isPaused = false;
// 遍历所有的 Request
for (Request request : Util.getSnapshot(requests)) {
// 如果 Request 没有在 Running 状态,调用对应的 begin() 方法
if (!request.isComplete() && !request.isRunning()) {
request.begin();
}
}
// 清除暂停的 Request 的列表
pendingRequests.clear();
}
上面代码非常简单,遍历所有的暂停的 Request
然后调用其对应的 begin()
方法恢复请求。
我们再来看看 TargetTracker#onStart()
方法的源码:
Java
@Override
public void onStart() {
for (Target<?> target : Util.getSnapshot(targets)) {
target.onStart();
}
}
朴实无华的代码,遍历所有的 Target
然后调用其 onStart()
方法。
我们来看看 ImageViewTarget#onStart()
方法是如何处理的:
Java
@Override
public void onStart() {
if (animatable != null) {
animatable.start();
}
}
其实也就是恢复没有执行完成的动画。
onStop()
在 onStop()
生命周期中会暂停没有完成的 Request
,虽然说是暂停,其实并不是真正的暂停,而且网络调用也并不能暂停,Glide
中所谓的暂停,其实就是暂停处理回调成功后的结果,等到下次 onStart()
后再继续处理。我们继续看看 RequestManager#onStop()
的实现:
Java
@Override
public synchronized void onStop() {
// 调用 Target 的 onStop() 生命周期
targetTracker.onStop();
if (clearOnStop) {
// 清除没有完成的 Request
clearRequests();
} else {
// 暂停没有完成的 Request
pauseRequests();
}
}
首先通过 TargetTracker#onStop()
方法通知 Target
的 onStop()
生命周期;后续的代码分为两种情况:通过 pauseRequests()
方法暂停没有完成的 Request
(这也是默认的处理方式);通过 clearRequests()
方法清除没有完成的 Request
(我们讲 onDestroy()
的时候再讲这个方法)。
我们看看 ImageViewTarget#onStop()
怎么处理 onStop()
生命周期的:
Java
@Override
public void onStop() {
if (animatable != null) {
animatable.stop();
}
}
和 onStart()
生命周期对应,就是停止正在执行的动画。
继续看看 pauseRequests()
方法是如何暂停 Request
的:
Java
public synchronized void pauseRequests() {
requestTracker.pauseRequests();
}
继续追踪 RequestTracker#pauseRequsts()
方法:
Java
public void pauseRequests() {
isPaused = true;
for (Request request : Util.getSnapshot(requests)) {
if (request.isRunning()) {
request.pause();
pendingRequests.add(request);
}
}
}
遍历所有的 Request
,如果正在运行,那么调用 Request#pause()
方法,同时将对应的 Request
添加到 pendingRequests
列表中。
我们在前面的文章中知道,Request
真正的实现类是 SingleRequest
,我们来看看 SingleRequest#pause()
是怎么实现的:
Java
@Override
public void pause() {
synchronized (requestLock) {
if (isRunning()) {
clear();
}
}
}
继续调用对应的 clear()
方法:
Java
@Override
public void clear() {
Resource<R> toRelease = null;
synchronized (requestLock) {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
if (status == Status.CLEARED) {
return;
}
cancel();
// Resource must be released before canNotifyStatusChanged is called.
if (resource != null) {
toRelease = resource;
resource = null;
}
if (canNotifyCleared()) {
target.onLoadCleared(getPlaceholderDrawable());
}
GlideTrace.endSectionAsync(TAG, cookie);
status = Status.CLEARED;
}
if (toRelease != null) {
engine.release(toRelease);
}
}
上面代码会继续调用 cancel()
方法,然后将状态更新为 CLEARED
,还可能通知 Target#onLoadCleared()
方法,这里的参数用的是 PlaceholderDrawable()
。如果当前的 Resource
不为空,还会将其释放。
我们来看看 cancel()
方法的实现:
Java
private void cancel() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
target.removeCallback(this);
if (loadStatus != null) {
loadStatus.cancel();
loadStatus = null;
}
}
首先将 Target
的 Size
回调从 Target
中移除,然后调用 LoadStatus#cancel()
方法。加载 Target
的 Size
在第四篇文章中说过,这个 LoadStatus
是 Engine#load()
方法返回的,用它来控制加载过程中任务,在第四篇文章中也说过。
Java
public void cancel() {
synchronized (Engine.this) {
engineJob.removeCallback(cb);
}
}
其实就是简单将请求成功/失败的回调从 EngineJob
中移除,可能你忘记了这个 Callback
是什么时候添加进去的,在第四篇文章中讲过,我们再回忆回忆 SingleRequest#onSizeReady()
方法:
Java
@Override
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#load()
方法传递的 this
其实就是上面被移除的 Callback
。所以 Glide
中的暂停其实就是将 SingleRequest
中的 Callback
移除,这会影响后续的 Target
的渲染相关的 UI
流程,但是并不会影响 Engine
中对内存缓存,磁盘缓存的逻辑处理,所以当下次 SingleRequest
恢复时,它就能够直接从内存缓存中或者磁盘缓存中快速加载,而不用再请求网络。
onDestroy()
onDestroy()
也表明 RequestManager
到了生命末期,它和它其中的 Request
与 Target
也都需要被销毁而且都不能够再恢复。
Java
@Override
public synchronized void onDestroy() {
// 对 Target 回调 onDestroy 生命周期
targetTracker.onDestroy();
// 移除 Target 中引用的 Request
clearRequests();
// 清除所有的 Request
requestTracker.clearRequests();
// 移除 RequestManager 对生命周期的监听
lifecycle.removeListener(this);
// 移除 ConnectiveityMonitor 对生命周期的监听
lifecycle.removeListener(connectivityMonitor);
Util.removeCallbacksOnUiThread(addSelfToLifecycle);
// 通知 Glide 当前 RquestManager 被移除。
glide.unregisterRequestManager(this);
}
ImageViewTarget
中是把 Request
存放在 ImageView
的 Tag
中,前面有说到过,我这里再啰嗦下。然后我们再看看 RequestTracker#clearRequests()
方法是如何清除 Request
的(注意区分和 pauseRequests()
方法处理的方式):
Java
public void clearRequests() {
for (Request request : Util.getSnapshot(requests)) {
// It's unsafe to recycle the Request here because we don't know who might else have a
// reference to it.
clearAndRemove(request);
}
pendingRequests.clear();
}
遍历所有的 Request
并调用 clearAndRemove()
方法,同时清空 pendingRequests
中暂停的 Request
。
我们看看 clearAndRemove()
方法的实现:
Java
public boolean clearAndRemove(@Nullable Request request) {
if (request == null) {
// If the Request is null, the request is already cleared and we don't need to search further
// for its owner.
return true;
}
boolean isOwnedByUs = requests.remove(request);
// Avoid short circuiting.
isOwnedByUs = pendingRequests.remove(request) || isOwnedByUs;
if (isOwnedByUs) {
request.clear();
}
return isOwnedByUs;
}
上面会将所有 Request
从 requests
和 pendingRequests
中移除,同时调用 Request#clear()
方法(这个方法我们上面已经分析过了),而 resumeRequests()
方法中并不会将 Request
从 reuqests
中移除,而且会将 Request
添加到 pendingRequests
中去,供下次恢复时再调用对应的 begin()
方法。
最后
本篇文章介绍了 Glide
如何加载网络请求的数据和如何写入磁盘缓存(包括 ResourceCache
和 DataCache
);还介绍了 RequestManager
具体如何处理不同的 Android
生命周期。