RequestManager主要有两个作用:
1.创建RequestBuilder;
2.通过生命周期管理请求的启动结束等;
这篇文章会涉及到这么几个类:RequestManager、RequestBuilder、RequestOptions、BaseRequestOptions
创建RequestBuilder入口方法是as(Class<ResourceType> resourceClass):
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
该方法由asDrawable(), asBitmap(), asGif(), asFile()调用,我们应该很少调用asDrawable()这几个方法,一般情况是直接使用load重载方法,比如:load(Bitmap bitmap), load(Drawable drawable), load(String string), load(byte[] bytes)……,在load()重载方法内部其实都是调用了asDrawable()方法后创建了RequestBuilder再调用了RequestBuilder的load()方法传入加载的来源类型。还有2个供下载的方法:RequestBuilder<File> downloadOnly();RequestBuilder<File> download(@Nullable Object model);
load()方法传入了数据源,Glide称之为model,是调用了loadGeneric()实现的:
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
先来看下RequestBuilder的定义、构造函数、常用入口函数:
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>
implements Cloneable,
ModelTypes<RequestBuilder<TranscodeType>>
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());
}
public RequestBuilder<TranscodeType> apply(@NonNull BaseRequestOptions<?> requestOptions) {
return super.apply(requestOptions);
}
RequestBuilder继承了BaseRequestOptions,可以保存各种加载图片需要的属性,Glide称之为RequestOptions,构造时传入全局glide、requestManager、transcodeClass(期望将图片转换成哪种类型,比如Drawable、Bitmap……)、context、transitionOptions(TODO 这个还不知道是干什么的)、glideContext。一般的用法会设置好requestOptions传入apply()方法,RequestBuilder调用父类apply()方法整合这些options。
再来看参数RequestOptions,这个类就一两百行,几乎都是工厂方法实现了各种加载图片需要的属性,比如占位图片的实现:
public static RequestOptions placeholderOf(@DrawableRes int placeholderId) {
return new RequestOptions().placeholder(placeholderId);
}
RequestOptions本身没有真正实现placeholder,它没有定义成员变量来保存上面的参数placeholderId,可以认为是一个工具类、包装类,它的定义是:
public class RequestOptions extends BaseRequestOptions<RequestOptions>
即继承自BaseRequestOptions<RequestOptions>,所以上面举例的代码片段中placeholder()的实现是在BaseRequestOptions中。
现在不得不来看下BaseRequestOptions类了,下面摘录了一段代码,还是以上面的placeholder()为例子:
public abstract class BaseRequestOptions<T extends BaseRequestOptions<T>> implements Cloneable {
private static final int PRIORITY = 1 << 3;
private static final int ERROR_PLACEHOLDER = 1 << 4;
private static final int ERROR_ID = 1 << 5;
private static final int PLACEHOLDER = 1 << 6;
private static final int PLACEHOLDER_ID = 1 << 7;
private int fields;
private DiskCacheStrategy diskCacheStrategy = DiskCacheStrategy.AUTOMATIC;
private Priority priority = Priority.NORMAL;
private Drawable placeholderDrawable;
private int placeholderId;
private boolean isCacheable = true;
private Key signature = EmptySignature.obtain();
private Options options = new Options();
private static boolean isSet(int fields, int flag) {
return (fields & flag) != 0;
}
public T placeholder(@DrawableRes int resourceId) {
if (isAutoCloneEnabled) {
return clone().placeholder(resourceId);
}
this.placeholderId = resourceId;
fields |= PLACEHOLDER_ID;
placeholderDrawable = null;
fields &= ~PLACEHOLDER;
return selfOrThrowIfLocked();
}
BaseRequestOptions是一个泛型类,其泛型参数就是泛型类BaseRequestOptions,即其泛型参数就是自身,这种用法看起来是装饰器模式。在BaseRequestOptions里定义了各种属性比如placeholderId、priority……,成员变量fields通过位运算记录了哪些属性被设置过。有些属性可以通过不同的参数赋值,比如placeholderId,以resourceId形式设置了placeholder又可以以drawable形式设置placeholder,因此fields需要对另一种形式取反,只能设置一种。
我们经常用到的load()、apply()方法都是会返回RequestBuilder,而RequestBuilder本身可以通过apply(BaseRequestOptions<?> requestOptions)方法接收其他属性设置,apply()的实现是在RequestBuilder的父类也就是BaseRequestOptions中,部分代码如下:
public T apply(@NonNull BaseRequestOptions<?> o) {
if (isAutoCloneEnabled) {
return clone().apply(o);
}
BaseRequestOptions<?> other = o;
if (isSet(other.fields, SIZE_MULTIPLIER)) {
sizeMultiplier = other.sizeMultiplier;
}
if (isSet(other.fields, DISK_CACHE_STRATEGY)) {
diskCacheStrategy = other.diskCacheStrategy;
}
if (isSet(other.fields, PRIORITY)) {
priority = other.priority;
}
if (isSet(other.fields, PLACEHOLDER)) {
placeholderDrawable = other.placeholderDrawable;
placeholderId = 0;
fields &= ~PLACEHOLDER_ID;
}
if (isSet(other.fields, PLACEHOLDER_ID)) {
placeholderId = other.placeholderId;
placeholderDrawable = null;
fields &= ~PLACEHOLDER;
}
// Applying options with dontTransform() is expected to clear our transformations.
if (!isTransformationAllowed) {
transformations.clear();
fields &= ~TRANSFORMATION;
isTransformationRequired = false;
fields &= ~TRANSFORMATION_REQUIRED;
isScaleOnlyOrNoTransform = true;
}
fields |= other.fields;
options.putAll(other.options);
return selfOrThrowIfLocked();
}
即通过对fields位运算来判断传入的RequestOptions是否有设置,有的话就更新。
RequestBuilder都设置好后,我们下一个调用的方法一般是into(),部分代码如下:
private <Y extends Target<TranscodeType>> Y into(Y target, RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options,Executor callbackExecutor){
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
previous.begin();
}
return target;
}
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
into()方法有个小细节,即第三个参数BaseRequestOptions options 是RequestBuilder本身(RequestBuilder继承自BaseRequestOptions)。如果target是ImageView,那么会判断之前是否设置了transformation(这个后面再展开),如果没有且ImageView的getScaleType() != null,那么会读取ScaleType来更新RequestBuilder本身。
回到into()方法,生成Request,并判断加载图片的target容器之前是否有Request,如果有且两者相等就判断老的Request是否完成,完成则也调用begin(),如果失败则调用begin()给予重试的机会。如果是新的Request那么调用3个方法:
1.requestManager.clear(target); 取消与target有关的等待实施的加载、释放target已经使用过的资源(比如bitmap)以便复用,因为接下来要设置新的Request了。其内部实现是untrackOrDelegate()方法,这里还没有空明白。TODO
2.target.setRequest(request);保存request,如果是CustomViewTarget则通过setTag(int key, Object obj)的方式保存request,如果是CustomTarget则直接保存为其成员变量,关于Target我会写到另一篇文章里;
3.requestManager.track(target, request); 这里就是真正的开始请求了,放到另一篇文章里写;
至此,RequestBuilder涉及到的流程就应该走完了,接下来就和Request有关了,当然RequestBuilder里面还有一些其他的成员变量、方法没有分析到,后面遇到问题再补充。
然后这篇文章还缺少RequestManager是如何通过生命周期来管理请求的启动、结束的,下次再补充 TODO