Glide源码——RequestManager

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值