SingleRequest
上一篇分析到生成Request,接下来我们直接从SingleRequest子类开始阅读。
大致的流程:begin -> onSizeReady->engine.load
public void begin() {
synchronized (requestLock) {
...
//model为空回调失败
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
//Status.RUNNING抛异常
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
//Status.COMPLETE,回调onResourceReady
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE, false);
return;
}
experimentalNotifyRequestStarted(model);
cookie = GlideTrace.beginSectionAsync(TAG);
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()) {
//ImageView设置占位图
target.onLoadStarted(getPlaceholderDrawable());
}
}
}
begin方法处理了两种逻辑:
- 判断Request各种状态,然后回调
- 判断输出大小是否确认。确认的情况调用onSizeReady。不确认的情况调用getSize,getSize方法传递的参数是callback,所以等待大小确认后,最后还是回调到onSizeReady
getSize
如果into的是ImageView,生成的是ImageViewTarget。
void getSize(@NonNull SizeReadyCallback cb) {
....
if (layoutListener == null) {
ViewTreeObserver observer = view.getViewTreeObserver();
layoutListener = new SizeDeterminerLayoutListener(this);
observer.addOnPreDrawListener(layoutListener);
}
}
监听的原理是通过ViewTreeObserver,view大小确认后,最后执行到关键方法getTargetDimen
private int getTargetDimen(int viewSize, int paramSize, int paddingSize) {
//布局xml固定大小的情况
int adjustedParamSize = paramSize - paddingSize;
if (adjustedParamSize > 0) {
return adjustedParamSize;
}
//martch_parent的情况,需要等待view的大小测量成功
int adjustedViewSize = viewSize - paddingSize;
if (adjustedViewSize > 0) {
return adjustedViewSize;
}
//WRAP_CONTENT取屏幕大小
if (!view.isLayoutRequested() && paramSize == LayoutParams.WRAP_CONTENT) {
return getMaxDisplayLength(view.getContext());
}
return PENDING_SIZE;
}
大小确认后回调到SingleRequest.OnSizeReady方法,里面主要是执行到engine.load方法
Engine
public <R> LoadStatus load(...) {
//生成key
EngineKey key =
keyFactory.buildKey(...);
//根据key取缓存
EngineResource<?> memoryResource;
synchronized (this) {
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
//没缓存,开始异步任务获取图片资源
if (memoryResource == null) {
return waitForExistingOrStartNewJob(...);
}
}
Key
public interface Key {
void updateDiskCacheKey(@NonNull MessageDigest messageDigest);
@Override
boolean equals(Object o);
@Override
int hashCode();
}
- updateDiskCacheKey是用于生成磁盘缓存的key。原理是通过MessageDigest.update(...)方法更新数据摘要,MessageDigest.digest()输出摘要,然后根据摘要key获取已经缓存好的磁盘文件
- equals和hashCode都是object的方法,目的是确保实现Key接口的子类重写equals和hahCode,判断Key的相同性
上面engine生成的EngineKey代码如下:
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
buildKey的入参8个,需要8个值相同,EngineKey才会相同。第二个入参signature是通过RequestBuilder.signature(@NonNull Key signature)设置的,作用是预留扩展性,例如我们想把app的版本号加进key判断,就可以自定义key更改配置。
loadFromMemory
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
return active;
}
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
return cached;
}
return null;
}
- 内存缓存有两种。loadFromActiveResources(key)指活跃中ImageView显示中的资源。loadFromCache(key)是不活跃的资源已经不在ImageView显示,存储在MemoryCache。
- isMemoryCacheable字段是通过RequestBuilder.skipMemoryCache(boolean skip)设置,默认值支持缓存
waitForExistingOrStartNewJob
里面的逻辑比较简单,通过工厂生成EngineJob和DecodeJob,然后调用start开始加载。EngineJob和DecodeJob这两个类我们后面再详细分析。