Glide源码加载流程分析一

前言

阅读源码应该认准一个功能点(主线),然后去分析这个功能点是如何实现的。千万不要试图去搞懂每一行代码都是什么意思,那样很容易会陷入到源码中,而且越陷越深。

Glide 使用简明的流式语法API,在大部分情况下一行代码即可搞定需求:

Glide.with(fragment)
    .load(url)
    .into(imageView);

取消加载同样很简单:

Glide.with(fragment).clear(imageView);

尽管及时取消不必要的加载是很好的习惯,但这并不是必须的操作。实际上,当 Glide.with() 中传入的 Activity 或 Fragment 实例销毁时,Glide 会自动取消加载并回收资源。Glide的使用非常简单,但是简单的背后,隐藏了复杂的实现,源码内容非常多。

with.png

Glide.with

Glide类是单例模式,其中重载了多个with方法,允许我们传递上下文(Context)以及能够获得上下文的Fragment与View。

所有的with方法中的实现均为:

//Glide
public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
}
    
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    return Glide.get(context).getRequestManagerRetriever();
}

主要做了两件事情:

  1. 通过get方法获得Glide单例对象并获取其成员属性:RequestManagerRetriever;
  2. 通过RequestManagerRetriever的get方法获得RequestManager。

RequestManagerRetriever

RequestManagerRetriever的功能就是获得RequestManager请求管理者。Glide中所有加载图片的请求都是由请求管理器进行管理。为了进行自动生命周期的管理,请求管理器与Glide.with方法传递的不同参数相对应。

Glide.with参数:

  • 传递Activity,则此次加载图片会在退出Activity后自动取消;
  • 传递Fragment,则加载图片会在Fragment销毁时取消;
  • 传递Application,那么Glide将无法管理图片请求生命周期。

换句话说,每一个Activity存在一个对应的RequestManager,每一个不同的Fragment也有其对应的RequestManager,而整个应用运行阶段同样会有一个RequestManager。这些不同的RequestManager通过RequestManagerRetriever.get获取。RequestManagerRetriever同样重载了多个get方法,以get(FragmentActivity)为例:

//RequestManagerRetriever
public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
}
  • 若非主线程,则使用Application上下文调用get重载方法get(Context),直接返回自己的成员属性RequestManager类型的applicationManager
  • 若在主线程,则获得Activity对应的FragmentManager来获得RequestManager。

对于主线程的情况,Glide为了进行生命周期管理,在Activity#onDestory时取消图片加载。那么如何监听到Activity的onDestory回调?如果向此Activity中添加一个Fragment,当Activity销毁时,Activity中附加的Fragment同样也会销毁。事实上实现也确实如此,在获得了Activity对应的FragmentManager之后,supportFragmentGet的实现为:

//RequestManagerRetriever
private RequestManager supportFragmentGet(@NonNull Context context,@NonNull FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
}

其中getSupportRequestManagerFragment(fm, parentHint, isParentVisible)就是获得附加在对应Activity的Fragment,而此Fragment中存在成员RequestManager。如果此成员不为null,则直接返回,否则创建并设置进入Fragment之后再返回。

小结

with时序图.png
  • 构建 Glide 实例;
  • 获取 RequestManagerRetriever 对象;
  • 构建 RequestManager 对象。
    • 若传递Activity/Fragment并为主线程调用, 则为 Activity/Fragment 添加一个 RequestManagerFragment, 其内部含有 ReqeustManager 对象;
    • 否则, 获取一个相当于单例的 applicationManager 专门用于处理这类请求。

RequestManager.load

Glide.with获得RequestManager之后,执行load方法设置图片源。图片源可以是:图片数据字节数组、File文件,网络图片地址等。以load(String)为例:

//RequestManager
public RequestBuilder load(@Nullable String string) {
    return asDrawable().load(string);
}
public RequestBuilder asDrawable() {
    return as(Drawable.class);
}
public  RequestBuilder as(
      @NonNull Class resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
}

load方法默认设置目标资源为 Drawable,获得一个RequestBuilder。紧接着调用RequestBuilder.load方法记录加载的model(图片源)。

//RequestBuilder
public RequestBuilder load(@Nullable String string) {
    return loadGeneric(string);
}
@NonNull
private RequestBuilder loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
}

RequestBuilder是请求构建者,用户可以使用它设置如:单独的缓存策略、加载成功前占位图、加载失败后显示图片等等加载图片的各种配置。当RequestBuilder 构建完成之后,接下来就等待执行这个请求。

RequestBuilder.into

使用Glide最简单的方式加载图片最后一个阶段就是执行into方法。从into方法为入口开始执行图片加载,逻辑也开始复杂起来。

//RequestBuilder
@NonNull
  public ViewTarget into(@NonNull ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    BaseRequestOptions requestOptions = this;
    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,
        Executors.mainThreadExecutor());
  }

一般来说,我们在执行into时传入一个ImageView用于显示。在这个into方法中,先确定本次加载的BaseRequestOptions,然后执行重载的另一个into方法。其中BaseRequestOptions就是上面我们提到的RequestBuilder可以设置图片加载的各种配置,这些配置选项就被封装在BaseRequestOptions中(RequestBuilder extends BaseRequestOptions)。而重载的into方法实现为:

//RequestBuilder

private > Y into(
      @NonNull Y target,
      @Nullable RequestListener targetListener,
      BaseRequestOptions options,
      Executor callbackExecutor) {
    Preconditions.checkNotNull(target);
    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)) {
      // 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方法中首先调用 buildRequest 构建了一个请求Request,然后把Request交给RequestManager跟踪(生命周期)并启动请求。

你可能感兴趣的:(Glide源码加载流程分析一)