Glide源码分析(二)——从用法来看之load&into方法

上一篇,我们分析了with方法,文章链接:
https://blog.csdn.net/qq_36391075/article/details/82833260

在with方法中,进行了Glide的初始化,创建了RequesManger,并且绑定了生命周期,最终返回了一个RequestManager,现在,我们就来分析分析load方法:

同样load方法也有很多重载方法:

 public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
    
    return asDrawable().load(bitmap);
  }

 public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
    
    return asDrawable().load(drawable);
  }

public RequestBuilder<Drawable> load(@Nullable String string) {
    
    return asDrawable().load(string);
  }

 public RequestBuilder<Drawable> load(@Nullable Uri uri) {
    
    return asDrawable().load(uri);
  }

 public RequestBuilder<Drawable> load(@Nullable File file) {
    
    return asDrawable().load(file);
  }

public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
    
    return asDrawable().load(resourceId);
  }

 public RequestBuilder<Drawable> load(@Nullable URL url) {
    
    return asDrawable().load(url);
  }

 public RequestBuilder<Drawable> load(@Nullable byte[] model) {
    
    return asDrawable().load(model);
  }

public RequestBuilder<Drawable> load(@Nullable Object model) {
    
    return asDrawable().load(model);
  }

上面这些是它的所有的重载,我们可以看到,无论是哪个重载方法,都会先调用asDrawable(),所以看看吧:

 /**
   * Attempts to always load the resource using any registered {@link
   * com.bumptech.glide.load.ResourceDecoder}s that can decode any subclass of {@link Drawable}.
   *尝试使用使用任何已经注册的了可以解码Drawable机及其子类的ResourceDecoder如加载资源
   *
   *
   * <p> By default, may return either a {@link android.graphics.drawable.BitmapDrawable} or {@link
   * GifDrawable}, but if additional decoders are registered for other {@link Drawable} subclasses,
   * any of those subclasses may also be returned. </p>
   *
   * @return A new request builder for loading a {@link Drawable}.
   */
  @NonNull
  @CheckResult
  public RequestBuilder<Drawable> asDrawable() {
    
    return as(Drawable.class);
  }

 /**
   * Attempts to load the resource using any registered
   * {@link com.bumptech.glide.load.ResourceDecoder}s
   * that can decode the given resource class or any subclass of the given resource class.
   *
   * @param resourceClass The resource to decode.
   * @return A new request builder for loading the given resource class.
   */
  @NonNull
  @CheckResult
  public <ResourceType> RequestBuilder<ResourceType> as(
      @NonNull Class<ResourceType> resourceClass) {
    
    return new RequestBuilder<>(glide, this, resourceClass, context);
  }

我们可以看到asDrawable方法最终返回了一个RequestBuilder对象,RequestBuilder是什么呢?

public class RequestBuilder<TranscodeType> implements Cloneable,
    ModelTypes<RequestBuilder<TranscodeType>> 

还是先看官网描述:

  A generic class that can handle setting options and staring loads
  for generic resource types.
 
  @param <TranscodeType> The type of resource that will be delivered to the
  {
    @link com.bumptech.glide.request.target.Target}.
 

ReqestBuilder是一个通用类,可以处理设置的选项和启动加载通用resource类型。

它的构造方法:

protected RequestBuilder(Glide glide, RequestManager requestManager,
      Class<TranscodeType> transcodeClass, Context context) {
    
    this.glide = glide;
    this.requestManager = requestManager;
    this.transcodeClass = transcodeClass;
    this.defaultRequestOptions = requestManager.getDefaultRequestOptions();
    this.context = context;
    this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
    this.requestOptions = defaultRequestOptions;
    this.glideContext = glide.getGlideContext();
  }

回到load方法,调用asDrawable方法得到RequestBuilder后,调用了RequestBuilder.load方法:
RequestBuilder中也有一堆load重载方法:

 public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
    
    return loadGeneric(bitmap)
        .apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
  }

 public RequestBuilder<TranscodeType> load(@Nullable byte[] model) {
    
    RequestBuilder<TranscodeType> result = loadGeneric(model);
    if (!result.requestOptions.isDiskCacheStrategySet()) {
    
        result = result.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
    }
    if (!result.requestOptions.isSkipMemoryCacheSet()) {
    
      result = result.apply(skipMemoryCacheOf(true /*skipMemoryCache*/));
    }
    return result;
  }

public RequestBuilder<TranscodeType> load(@Nullable Drawable drawable) {
    
    return loadGeneric(drawable)
        .apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
  }

 public RequestBuilder<TranscodeType> load(@Nullable File file) {
    
    return loadGeneric(file);
  }

public RequestBuilder<TranscodeType> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
    
    return loadGeneric(resourceId).apply(signatureOf(ApplicationVersionSignature.obtain(context)));
  }

 public RequestBuilder<TranscodeType> load(@Nullable Object model) {
    
    return loadGeneric(model);
  }
  
public RequestBuilder<TranscodeType> load(@Nullable String string) {
    
    return loadGeneric(string);
  }

 public RequestBuilder<TranscodeType> load(@Nullable Uri uri) {
    
    return loadGeneric(uri);
  }

上面就是它的所有的重载方法了,同样,都先调用了loadGeneric()方法:

@NonNull
  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }

这个方法中只是简单的进行赋值操作,此处的model就是我们请求地址的String串。

load方法就这样完了,我们接着往下看:

into方法

同样的,into方法也有很多重载:

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    RequestOptions requestOptions = this.requestOptions;
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
    
      // Clone in this method so that if we use this RequestBuilder to load into a View and then
      // into a different target, we don't retain the transformation applied based on the previous
      // View's scale type.
      switch (view.getScaleType()) {
    
        case CENTER_CROP:
          requestOptions = requestOptions.clone().optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions = requestOptions.clone().optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.
      }
    }

    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions);
  }

 public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
    
    return into(target, /*targetListener=*/ null);
  }


  @NonNull
  @Synthetic <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener) {
    
    return into(target, targetListener, getMutableOptions());
  }

 private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @NonNull RequestOptions options) {
    
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
    
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    options = options.autoClone();
    Request request = buildRequest(target, targetListener, options);

    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方法,对于我们比较收悉的第一个into,会保证ImageView的ScaleType到requestOptions。
现在我们就一起看看最后有个into方法:

private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @NonNull RequestOptions options) {
    
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
    
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    options = options.autoClone();
    //构建Request对象
    Request request = buildRequest(target, targetListener, options);
	//得到之前的Request
    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)//如果target的Request与当前新构建的Request相同,则重用
        && !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;
    }
	//否则,就将新苟安的request设置给target,同时由requestManager负责监督request的执行过程
    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
  }

上面代码,总的来说就是,先构建Request,如果新的Request和老的Request相同,就重用,否则就重新执行

于是,我们就先看看Request的构建过程吧:

首先我们还是先看看这个Request是什么鬼:

/**
 * A request that loads a resource for an {@link com.bumptech.glide.request.target.Target}.
 */
public interface Request {
    

  /**
   * Starts an asynchronous load.
   */
  void begin();

  /**
   * Identical to {@link #clear()} except that the request may later be restarted.
   */
  void pause();

  /**
   * Prevents any bitmaps being loaded from previous requests, releases any resources held by this
   * request, displays the current placeholder if one was provided, and marks the request as having
   * been cancelled.
   */
  void clear();

  /**
   * Returns true if this request is paused and may be restarted.
   */
  boolean isPaused();

  /**
   * Returns true if this request is running and has not completed or failed.
   */
  boolean isRunning();

  /**
   * Returns true if the request has completed successfully.
   */
  boolean isComplete();

  /**
   * Returns true if a non-placeholder resource is put. For Requests that load more than one
   * resource, isResourceSet may return true even if {@link #isComplete()}} returns false.
   */
  boolean isResourceSet();

  /**
   * Returns true if the request has been cancelled.
   */
  boolean isCancelled();

  /**
   * Returns true if the request has failed.
   */
  boolean isFailed();

  /**
   * Recycles the request object and releases its resources.
   */
  void recycle();

  /**
   * Returns {@code true} if this {@link Request} is equivalent to the given {@link Request} (has
   * all of the same options and sizes).
   *
   * <p>This method is identical to {@link Object#equals(Object)} except that it's specific to
   * {@link Request} subclasses. We do not use {@link Object#equals(Object)} directly because we
   * track {@link Request}s in collections like {@link java.util.Set} and it's perfectly legitimate
   * to have two different {@link Request} objects for two different
   * {@link com.bumptech.glide.request.target.Target}s (for example). Using a similar but different
   * method let's us selectively compare {@link Request} objects to each other when it's useful in
   * specific scenarios.
   */
  boolean isEquivalentTo(Request other);
}

我们可以看到,Request只是一个接口,根据里面的方法,我们可以猜到它相当于图片加载时的控制回调接口:

private Request buildRequest(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      RequestOptions requestOptions) {
    
    return buildRequestRecursive(
        target,
        targetListener,
        /*parentCoordinator=*/ null,
        transitionOptions,
        requestOptions.getPriority(),
        requestOptions.getOverrideWidth(),
        requestOptions.getOverrideHeight(),
        requestOptions);
  }


 private Request buildRequestRecursive(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      RequestOptions requestOptions) {
    

    // Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
    ErrorRequestCoordinator errorRequestCoordinator = null;
    //v4支持error方法设置requestBuilder,也就是此处的errorBuilder
    if (errorBuilder != null) {
    
      errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }

    Request mainRequest =
        buildThumbnailRequestRecursive(
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions);
	
	//如果没有设置erroBuilder,则直接返回这个正常的请求
    if (errorRequestCoordinator == null) {
    
      return mainRequest;
    }

    int errorOverrideWidth = errorBuilder.requestOptions.getOverrideWidth();
    int errorOverrideHeight = errorBuilder.requestOptions.getOverrideHeight();
    //如果使用了,override方法重写了请求的图片的宽度和高度
    //则需要将其设置给errorBuilder用于构建errorRequest
    if (Util.isValidDimensions(overrideWidth, overrideHeight)
        && !errorBuilder.requestOptions.isValidOverride()) {
    
      errorOverrideWidth = requestOptions.getOverrideWidth();
      errorOverrideHeight = requestOptions.getOverrideHeight();
    }
	//如果设置了erroeBuilder,则构建一个errorRequest
    Request errorRequest = errorBuilder.buildRequestRecursive(
        target,
        targetListener,
        errorRequestCoordinator,
        errorBuilder.transitionOptions,
        errorBuilder.requestOptions.getPriority(),
        errorOverrideWidth,
        errorOverrideHeight,
        errorBuilder.requestOptions);
   //ErrorRequestCoordinator:此类的作用就是如果mainRequest执行失败,则执行errorRequest
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }

如果我们设置一个error(RequestBuilder),那么执行的流程就会是,先执行mainRequest,如果mainRequest执行失败,则执行errorRequest。

我们先看mainRequest的构建:

 private Request buildThumbnailRequestRecursive(
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      RequestOptions requestOptions) {
    
      //如果我们设置了thumbnail(RequestBuilder)
    if (thumbnailBuilder != null) {
    
      // Recursive case: contains a potentially recursive thumbnail request builder.
      if (isThumbnailBuilt) {
    
        throw new IllegalStateException("You cannot use a request as both the main request and a "
            + "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
      }

      TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
          thumbnailBuilder.transitionOptions;

      // Apply our transition by default to thumbnail requests but avoid overriding custom options
      // that may have been applied on the thumbnail request explicitly.
      if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
    
        thumbTransitionOptions = transitionOptions;
      }

      Priority thumbPriority = thumbnailBuilder.requestOptions.isPrioritySet()
          ? thumbnailBuilder.requestOptions.getPriority() : getThumbnailPriority(priority);

      int thumbOverrideWidth = thumbnailBuilder.requestOptions.getOverrideWidth();
      int thumbOverrideHeight = thumbnailBuilder.requestOptions.getOverrideHeight();
      if (Util.isValidDimensions(overrideWidth, overrideHeight)
          && !thumbnailBuilder.requestOptions.isValidOverride()) {
    
        thumbOverrideWidth = requestOptions.getOverrideWidth();
        thumbOverrideHeight = requestOptions.getOverrideHeight();
      }

      ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
      Request fullRequest =
          obtainRequest(
              target,
              targetListener,
              requestOptions,
              coordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overr
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值