Glide原理解析(一):加载流程分析

Glide 使用很简单:

Glide.with(Context).load(url).into(View)

所以,分成三个流程进行分析:

1. with

  // Glide.java
  public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
  }


with()方法有很多参数,这里只看Activity作为参数的情况。

  private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    return Glide.get(context).getRequestManagerRetriever();
  }

RequestManagerRetriever 是检索者的意思,负责创建RequestManager,或者从Activity或Fragment找出RequestManager

Glide是一个单例,在创建的时候生成很多配置对象,比如RequestManagerRetriever 、缓存对象等。

RequestManager 顾名思义,就是负责管理Request 请求,而且会跟着Fragment或Activity的生命周期

看一下 RequestManager 是怎么生成的

  // RequestManagerRetriever
  @NonNull
  public RequestManager get(@NonNull Context context) {
    if (context == null) {
      throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {
      if (context instanceof FragmentActivity) {
        return get((FragmentActivity) context);
      } else if (context instanceof Activity) {
        return get((Activity) context);
      } else if (context instanceof ContextWrapper) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }
    return getApplicationManager(context);
  }

get()方法根据context是不同的实例,根据Context的类型是Application和非Application来获取不同的RequestManager;

这里我们只看context是Activity的情况

// RequestManagerRetriever
  public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) { // 如果非UI线程,走Application的ReqeustManager
      return get(activity.getApplicationContext());
    } else {
      android.app.FragmentManager fm = activity.getFragmentManager();
      // 获取FragmentManager 后续可以创建存储Fragment
      return fragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }
  
  private RequestManager fragmentGet(@NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    
    // 内部创建一个Fragment,构造RequestManager
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }


简述一下上面的RequestManager流程,主要目的是获取对应的FragmentManager,创建一个透明的Fragment;

getRequestManagerFragment()负责获取或者创建 SupportRequestManagerFragment(其实就是Fragment),不继续深究了,以流程为主;

这样 RequestManager自然就有了生命周期了的通知。

小结:
with() 目的是创建一个RequestManager

2.load()
RequestManager的 load() 方法返回的是一个ReqeustBuilder,分明是一个建造者模式,ReqeustBuilder负责创建Request;

RequestManager的大部分方法就是负责链式配置ReqeustBuilder的各种属性。

我们看一个最常用的load(),参数是一个String类型的URL

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

  public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
  }

 public <ResourceType> RequestBuilder<ResourceType> as(
      @NonNull Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
  }

看起来as()方法就是构造一个RequestBuilder,其中resourceClass表示资源类型,可以是Drawable、Bitmap、还有GifDrawable;

看完了asDrawable()构建好了RequestBuilder,最后看下ReqeustBuilder的load():

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

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

load(String )方法也是很简单的,大致上就是配置一下model 模型参数,表示我要加载的是什么model 模型参数,可以是uri、bitmap等等。

isModelSet是标记位,表示已设定好模型参数。

小结:
load() 目的是创建一个RequestBuilder,并配置各类参数

3. into()
以上构建好了RequestBuilder,来到最后一步RequestBuilder的into()方法,这是最重要也是最复杂的一步。

忍着头皮继续往下看吧。

这里只挑选into(ImageView)的方法

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    // 判断是否主线程
    Util.assertMainThread();
    Preconditions.checkNotNull(view);
    // 使用默认的 RequestOptions 配置
    RequestOptions requestOptions = this.requestOptions;
    // 判断是否需要自定义 transform 转换裁剪
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      // 根据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);
}

上面出现了一个RequestOptions,它保存着所有requestManager的配置,包括缓存策略、裁剪大小、动画效果、优先级等等。在用于创建reqeust的时候,配置reqeust的属性。

into(ImageView view) 根据scale type设定了一个对应的裁剪策略。

接着调用了glideContext.buildImageViewTarget(view, transcodeClass)创建一个ViewTarget。

最后重载的方法into()

我们先说下ViewTarget,它集成自BaseTarget,相当于是Glide处理完结果的回调,负责处理最后的结果,并且带有生命周期。

Glide提供了各种各样的Target:

ImageViewTargetFactory 负责创建ViewTarget:

public class ImageViewTargetFactory {
  public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
      @NonNull Class<Z> clazz) {
    if (Bitmap.class.equals(clazz)) {
      return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
      return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
    } else {
      throw new IllegalArgumentException(
          "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
  }
}

假定我们传的是Bitmap,返回的是一个BitmapImageViewTarget,我们在最后拿到结果的时候再回来分析BitmapImageViewTarget是如何处理的。

创建完了BitmapImageViewTarget,往下看重载的方法into(),基本是此次分析的重点流程:

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

    options = options.autoClone();
    // 1. 创建一个Request
    Request request = buildRequest(target, targetListener, options);
    // 2. 获取target之前的request
    Request previous = target.getRequest();
    
    // 3. 判断是否要开始这一次的请求
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      // 取消请求
      request.recycle();
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        // 开始之前的请求
        previous.begin();
      }
      return target;
    }
    // 4.先清除本次的target,再track开始此次请求
    requestManager.clear(target);
    target.setRequest(request);
    // 启动、追踪
    requestManager.track(target, request);

    return target;
  }

1. buildRequest() 会创建一个Request请求,内部会根据情况创建 三种请求:
ErrorRequestCoordinator 错误图片+目标图片联合请求(请求出错时,如有配置,则启动该请求)

ThumbnailRequestCoordinator 缩略图+目标图片联合请求(小图请求较快显示。如有配置,在请求开始时启动)

SingleRequest 目标图片请求(目标图片请求,在请求开始启动)

我们假定返回的SingleRequest请求

2. target.getRequest() 获取Target之前的请求
比如一个ImageView之前可能有一个Request正在请求或者执行完成。

这里我们看ViewTarget.getRequest()方法,个人觉得很有意思。

  // ViewTarget.java
  public Request getRequest() {
    Object tag = getTag();
    Request request = null;
    if (tag != null) {
      if (tag instanceof Request) {
        request = (Request) tag;
      } else {
        throw new IllegalArgumentException(
            "You must not call setTag() on a view Glide is targeting");
      }
    }
    return request;
  }
  
  public void setRequest(@Nullable Request request) {
    setTag(request);
  }

哈哈,原来Glide每次将Request都放进了View.setTag(Request)中,这样完成结果或者需要Request就可以从Tag中取出,好机智。

3. 判断此次请求是否还要继续
request.isEquivalentTo(previous)
用来判断是否是同样的请求

isSkipMemoryCacheWithCompletePreviousRequest(options, previous))
表示之前的请求已经完成并且这次的请求不缓存

4. requestManager.track(target, request) 开始此次真正的请求

 // RequestManager
  void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }

TargetTracker内部收录着所有的target,负责在收取到生命周期的时候通知所有的target,这里相当于target注册了成为观察者。

RequestTracker管理控制所有的request,负责启动、停止、管理所有的request。

  // RequestTracker
  public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      request.clear();
      pendingRequests.add(request);
    }
  }

上面假定了Request 是SingleRequest,直接看SingleRequest的begin()启动方法

  public void begin() {
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();
    if (model == null) { // model是在load()方法设定的,前面假定是String url
      // overrideWidth, overrideHeight是override()外部设定的裁剪的大小
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        width = overrideWidth;
        height = overrideHeight;
      }
      int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
      // sh
      onLoadFailed(new GlideException("Received null model"), logLevel);
      return;
    }
    // 重复请求
    if (status == Status.RUNNING) {
      throw new IllegalArgumentException("Cannot restart a running request");
    }
    // 重复请求已完成
    if (status == Status.COMPLETE) {
      onResourceReady(resource, DataSource.MEMORY_CACHE);
      return;
    }

    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      // 已经拿到了size,可以开始异步请求
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      // 从Target中获取目标的size,至于怎么保证拿到看后续问题,最后会走到onSizeReady()
      target.getSize(this);
    }

    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
        // onSizeReady是异步的,所以会调用target.onLoadedStarted(),显示占位符
      target.onLoadStarted(getPlaceholderDrawable());
    }
  }

上面的注释已经把流程标注得很清晰,最后看一个onSizeReady()方法

//SingleReqeust
public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled(); // 判断是否已经被释放
    if (status != Status.WAITING_FOR_SIZE) {
        return;
    }
    status = Status.RUNNING;

    float sizeMultiplier = requestOptions.getSizeMultiplier(); // 图像的尺寸系数(0 - 1)之间,用在缩略图
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier); // 根据尺寸系数算高度和宽度
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

    loadStatus = engine.load( // 调用Engine加载
        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);

    if (status != Status.RUNNING) {
        loadStatus = null;
    }
}

Engine内部包含了内存缓存和磁盘缓存,和怎么加载资源,这个在后续的缓存池模块继续分析;

最后会到Target的onResourceReady()成功回调

上面我们假定了Traget是 BitmapImageViewTarget,它继承自ImageViewTraget

  //ImageViewTraget
  public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
    if (transition == null || !transition.transition(resource, this)) { // 判断是否需要动画效果
      setResourceInternal(resource);
    } else {
      maybeUpdateAnimatable(resource);// 开始动画
    }
  }

  private void setResourceInternal(@Nullable Z resource) {
    setResource(resource); // setResource是抽象方法
    maybeUpdateAnimatable(resource);
  }

// BitmapImageViewTarget
  protected void setResource(Bitmap resource) {
    // View 就是最初的into中的ImageView
    view.setImageBitmap(resource);
  }

小结
into() 方法复杂无比,包括生命周期管理、缓存策略、裁剪、动画效果等等。

Glide.with(Conext).load(url).into(Image)

以上,基本分析完成了Glide最简单的链式调用的流程,这次尽量的省略大片大片的源码贴出,仅对整体流程加以把控。
 

猜你喜欢

转载自blog.csdn.net/suyimin2010/article/details/91353353