Glide4.0源码解析之一:Glide调用流程简析

今天开始更Glide4.0源码解析系列。

博主在面试过程中,经常遇到对使用过的开源项目源码解读的相关问题,之前对开源项目仅重视使用,没能做到知其然也知其所以然,所以从现在开始,准备出一些关于知名的开源项目的源码解读。感兴趣的同学可以一起交流学习,共同进步。下面开始今天的内容。

首先,让我们从Glide经常调用的方法看起,由于项目的源码量比较大,这样可以有助于我们找到切入点。加载网络图片时,一般调用Glide三步走操作如下:

Glide
    .with(context)
    .load(url)
    .into(myImageView);

我们分步来详细看一下这三步走的过程中,Glide帮助我们做了哪些事情。

注意:本文阅读时间较长,且涉及代码量较大,请阅读前做好准备并合理选择阅读时间。

一、Glide.with()方法

通过查看Glide类的代码可知 ,Glide.with()共有6个重载方法,分别是:

public static RequestManager with(Context context) {
    return getRetriever(context).get(context);
  }

public static RequestManager with(Activity activity) {
    return getRetriever(activity).get(activity);
  }

public static RequestManager with(android.support.v4.app.FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }

public static RequestManager with(android.support.v4.app.Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }

public static RequestManager with(android.app.Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }

public static RequestManager with(View view) {
    return getRetriever(view.getContext()).get(view);
  }

注意:

这里由于Glide加入了对android.support.v4.app.Fragment和android.support.v4.app.FragmentActivity的支持,所以我们在引入Glide的同时,也必须引入android.support.v4包。

这六个方法都调用了getRetriever(...)方法,返回一个RequestManagerRetriever对象,通过这个对象调用get(...)方法,最终调用fragmentGet()方法,通过RequestManagerFactory,创建Glide网络请求所需要的RequestManager对象,代码如下:

@SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"})
  @Deprecated
  @NonNull
  private RequestManager fragmentGet(@NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = getRequestManagerFragment(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;
  }

上述代码涉及到一个类,就是RequestManagerFragmentGlide源码注释解释为

/**
 * A view-less {@link android.app.Fragment} used to safely store an {@link
 * com.bumptech.glide.RequestManager} that can be used to start, stop and manage Glide 
 * requests started for targets the fragment or activity this fragment is a child of.
 */

翻译过来大概就是说这个Fragment是用来存储对应的FragmentActivity所使用的GlideRequestManager,并用来控制Glide请求的start、stop和合并。那么它是怎么控制的呢?参见代码如下:

RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
    this.lifecycle = lifecycle;
  }

@Override
  public void onStart() {
    super.onStart();
    lifecycle.onStart();
  }

  @Override
  public void onStop() {
    super.onStop();
    lifecycle.onStop();
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    lifecycle.onDestroy();
    unregisterFragmentWithRoot();
  }

RequestManagerFragment在其构造函数中传入了ActivityFragmentLifecycle,这个类回调了由RequestManager注册的LifecycleListener监听,这样,RequestManagerFragment根据自己生命周期的变化,就可以去对应修改RequestManager的状态。可以说,RequestManagerFragment就是Glide根据app页面情况管理自身请求状态的关键点。

至此,第一步结束,返回了RequestManager对象,为请求做准备。

二、load(url)方法

获得了对应页面的RequestManager,我们就可以进行下一步操作了。

当然,众所周知,Glide不止能加载网络图片,load(...)的重载方法多达9个,可传对象从Bitmap、Drawable、String到Uri、Url、File等等,具体方法如下:

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);
}

load(url)中调用了asDrawable()方法,asDrawable()调用as()方法创建一个新的RequestBuilder,并将资源类型传递给它:

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

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

RequestBuilder在构造方法中添加用户在GlideBuilder创建Glide时通过addGlobalRequestListener(...)方法添加的本地监听,并apply当前Glide定制请求的options:

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());
  }

asDrawable()方法返回RequestBuilder后继续调用load(url),并调用RequestBuilder的loadGeneric(url)方法。

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

第二步结束,返回了携带TranscodeTypeRequestBuilder。

三、into(view)方法

我们调用的into(view)方法源码如下:

public ViewTarget<ImageView, TranscodeType> 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),
        /*ta
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值