Glide源码分析(一),基本加载代码流程

本文分析了Glide的基本图片加载流程,从Glide#with方法开始,逐步讲解了Glide如何通过RequestManagerRetriever和RequestManager创建Request,以及如何处理生命周期和Target。重点介绍了with、getRetriever、get、RequestManagerRetriever、load和into等关键方法的调用链。通过对源码的剖析,展示了Glide如何在UI线程中构建和管理请求,以及如何利用生命周期监听确保适时的加载操作。
摘要由CSDN通过智能技术生成

下面来看在Glide中最简单的图片加载代码

       Glide.with(this)
                .load("https://p.upyun.com/docs/cloud/demo.jpg")
                .into(imageView);

这应该是相对比较简单的加载图片的代码了,一步步来,看代码其实很讲究耐心,有时候会遇到很多层次的调用链,这个时候其实很有必要自己画一些图,很能帮助理清一些思路。下面来看这段比较看似比较简单的代码,其实在Glide源码中,运用到了大量的类的设计,后面涉及的我会慢慢介绍到。

首先简单介绍下这个Glide类,它相当于是整个框架的调用入口,有一点像外观模式,一般很多第三方sdk都会用到这种模式,提供一个高层接口,减少用户的使用成本,对于我们第一个with方法,这个其实就是一个工厂方法,虽然有许多重载的形式,其实都是要创建一个RequestManager对象。下面我们来看这个
这个with方法,如下:

icon_glide_with.png

Glide#with方法有六个重载的形式,但是第一部分都是调用Glide#getRetriever获取一个RequestManagerRetriever对象,进而调用RequestManagerRetriever#get方法最终创建一个RequestManager对象。下面一个个来进行分析。

1.Glide#with

  @NonNull
  public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }

还有其他的重载形式,其实第一部分都是一样,都是获取他们(Actvity/View/Fragment等)的上下文,然后通过getRetriever方法去获取一个RequestManagerRetriever对象。进而得到一个RequestManager。

2.Glide#getRetriever

  @NonNull
  private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    // Context could be null for other reasons (ie the user passes in null), but in practice it will
    // only occur due to errors with the Fragment lifecycle.
    Preconditions.checkNotNull(
        context,
        "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
            + "returns null (which usually occurs when getActivity() is called before the Fragment "
            + "is attached or after the Fragment is destroyed).");
    return Glide.get(context).getRequestManagerRetriever();
  }

这个方法先是进行了context的非空检查,然后调用Glide#get方法

3.Glide#get

  @NonNull
  public static Glide get(@NonNull Context context) {
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context);
        }
      }
    }

    return glide;
  }

这个方法的主要逻辑是构建一个Glide的单例对象,初始化Glide对象时,做了很多复杂的配置信息,包括缓存策略等等,这里我们暂时跳过,后续讲到这些配置信息再详细分析,有时候,看代码要忽略其他的细节,沿着一条主线走,站在宏观的视角,针对具体问题再行微观分析,往往会比较清晰。这里获取到一个Glide实例之后,回到第2步,接下来回到Glide#getRetriever,然后是调用了Glide#getRequestManagerRetriever继续请求。

4.Glide#getRequestManagerRetriever

  @NonNull
  public RequestManagerRetriever getRequestManagerRetriever() {
    return requestManagerRetriever;
  }

这个方法很简单,就是返回一个RequestManagerRetriever对象,那么它是在什么时候初始化的呢,通过代码分析,在Glide初始化时候,会初始化这个requestManagerRetriever对象,我们暂且略过它。有了这个requestManagerRetriever对象后,回到第1步,接下来会调用RequestManagerRetriever#get方法,与Glide#with对应,它也有6个重载的形式,均是返回一个RequestManager。

5.RequestManagerRetriever#get

icon_request_manager_retriever_get.png

虽然是有这么多重载形式,但都是一个平行的关系,为了理解原理,去繁为简,其实我们完全可以只分析某一个,这里我们以参数为FragmentActivity为例,毕竟项目中其实大多数都是使用FragmentActivity了。

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

这里有两个分支,一个是ui线程,一个是非ui线程,这里我们先考虑在ui线程中的情况,把一条线走通,后续再来分析一些分支的情况。可以看到,在ui线程中,首先是获取了support下面的FragmentManager对象,然后继续调用supportFragmentGet。

6.RequestManagerRetriever#supportFragmentGet

 @NonNull
  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;
  }

这个方法有4个参数,以我们现在为例,parentHint为null,isParentVisible为true。还是一个道理,我们可以假定某一种情况,便于代码的主线分析。接下来是构建了一个SupportRequestManagerFragment对象,它就是一个Fragment对象,其实没有什么神秘,它里面绑定了一些Lifecycle的方法,后续我们会看到。这里其实用了一个技巧,因为我们看到,要跟踪一个Activity的生命周期,同时又要能够达到通用性,显然在用户的业务Activity中是不太可能能插入生命周期的钩子方法,那么,作为一个框架层面的,显然要必备一些通用性才行,这里Glide是通过手动添加一个隐藏的SupportRequestManagerFragment对象,通过监听它的生命周期变化而达到监听到宿主Activity生命周期的目的,显然,这里是完全可行的方案。我们先继续分析getSupportRequestManagerFragment这个方法的实现。

7.RequestManagerRetriever#getSupportRequestManagerFragment

  @NonNull
  private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingSupportRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值