Glide源碼分析(一)纬纪,基本加載代碼流程

原文:https://blog.csdn.net/nbsp22/article/details/80666592

下面來(lái)看在Glide中最簡(jiǎn)單的圖片加載代碼

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

這應(yīng)該是相對(duì)比較簡(jiǎn)單的加載圖片的代碼了求豫,一步步來(lái)右蒲,看代碼其實(shí)很講究耐心幢妄,有時(shí)候會(huì)遇到很多層次的調(diào)用鏈拟糕,這個(gè)時(shí)候其實(shí)很有必要自己畫(huà)一些圖判呕,很能幫助理清一些思路倦踢。下面來(lái)看這段比較看似比較簡(jiǎn)單的代碼,其實(shí)在Glide源碼中侠草,運(yùn)用到了大量的類的設(shè)計(jì)辱挥,后面涉及的我會(huì)慢慢介紹到。

首先簡(jiǎn)單介紹下這個(gè)Glide類边涕,它相當(dāng)于是整個(gè)框架的調(diào)用入口晤碘,有一點(diǎn)像外觀模式,一般很多第三方sdk都會(huì)用到這種模式功蜓,提供一個(gè)高層接口园爷,減少用戶的使用成本,對(duì)于我們第一個(gè)with方法式撼,這個(gè)其實(shí)就是一個(gè)工廠方法童社,雖然有許多重載的形式,其實(shí)都是要?jiǎng)?chuàng)建一個(gè)RequestManager對(duì)象著隆。下面我們來(lái)看這個(gè)
這個(gè)with方法扰楼,如下:

icon_glide_with.png

Glide#with方法有六個(gè)重載的形式,但是第一部分都是調(diào)用Glide#getRetriever獲取一個(gè)RequestManagerRetriever對(duì)象美浦,進(jìn)而調(diào)用RequestManagerRetriever#get方法最終創(chuàng)建一個(gè)RequestManager對(duì)象弦赖。下面一個(gè)個(gè)來(lái)進(jìn)行分析。

1.Glide#with

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

還有其他的重載形式浦辨,其實(shí)第一部分都是一樣蹬竖,都是獲取他們(Actvity/View/Fragment等)的上下文,然后通過(guò)getRetriever方法去獲取一個(gè)RequestManagerRetriever對(duì)象流酬。進(jìn)而得到一個(gè)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();
  }

這個(gè)方法先是進(jìn)行了context的非空檢查,然后調(diào)用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;
  }

這個(gè)方法的主要邏輯是構(gòu)建一個(gè)Glide的單例對(duì)象芽腾,初始化Glide對(duì)象時(shí)劈榨,做了很多復(fù)雜的配置信息,包括緩存策略等等晦嵌,這里我們暫時(shí)跳過(guò)同辣,后續(xù)講到這些配置信息再詳細(xì)分析,有時(shí)候惭载,看代碼要忽略其他的細(xì)節(jié)旱函,沿著一條主線走,站在宏觀的視角描滔,針對(duì)具體問(wèn)題再行微觀分析棒妨,往往會(huì)比較清晰。這里獲取到一個(gè)Glide實(shí)例之后,回到第2步券腔,接下來(lái)回到Glide#getRetriever伏穆,然后是調(diào)用了Glide#getRequestManagerRetriever繼續(xù)請(qǐng)求。

4.Glide#getRequestManagerRetriever

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

這個(gè)方法很簡(jiǎn)單纷纫,就是返回一個(gè)RequestManagerRetriever對(duì)象枕扫,那么它是在什么時(shí)候初始化的呢,通過(guò)代碼分析辱魁,在Glide初始化時(shí)候烟瞧,會(huì)初始化這個(gè)requestManagerRetriever對(duì)象,我們暫且略過(guò)它染簇。有了這個(gè)requestManagerRetriever對(duì)象后参滴,回到第1步,接下來(lái)會(huì)調(diào)用RequestManagerRetriever#get方法锻弓,與Glide#with對(duì)應(yīng)砾赔,它也有6個(gè)重載的形式,均是返回一個(gè)RequestManager青灼。

5.RequestManagerRetriever#get

icon_request_manager_retriever_get.png

雖然是有這么多重載形式过蹂,但都是一個(gè)平行的關(guān)系,為了理解原理聚至,去繁為簡(jiǎn),其實(shí)我們完全可以只分析某一個(gè)本橙,這里我們以參數(shù)為FragmentActivity為例扳躬,畢竟項(xiàng)目中其實(shí)大多數(shù)都是使用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));
    }
  }

這里有兩個(gè)分支甚亭,一個(gè)是ui線程贷币,一個(gè)是非ui線程,這里我們先考慮在ui線程中的情況亏狰,把一條線走通役纹,后續(xù)再來(lái)分析一些分支的情況∠就伲可以看到促脉,在ui線程中,首先是獲取了support下面的FragmentManager對(duì)象策州,然后繼續(xù)調(diào)用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;
  }

這個(gè)方法有4個(gè)參數(shù),以我們現(xiàn)在為例够挂,parentHint為null旁仿,isParentVisible為true。還是一個(gè)道理孽糖,我們可以假定某一種情況枯冈,便于代碼的主線分析毅贮。接下來(lái)是構(gòu)建了一個(gè)SupportRequestManagerFragment對(duì)象,它就是一個(gè)Fragment對(duì)象尘奏,其實(shí)沒(méi)有什么神秘滩褥,它里面綁定了一些Lifecycle的方法,后續(xù)我們會(huì)看到罪既。這里其實(shí)用了一個(gè)技巧铸题,因?yàn)槲覀兛吹剑櫼粋€(gè)Activity的生命周期琢感,同時(shí)又要能夠達(dá)到通用性丢间,顯然在用戶的業(yè)務(wù)Activity中是不太可能能插入生命周期的鉤子方法,那么驹针,作為一個(gè)框架層面的烘挫,顯然要必備一些通用性才行,這里Glide是通過(guò)手動(dòng)添加一個(gè)隱藏的SupportRequestManagerFragment對(duì)象柬甥,通過(guò)監(jiān)聽(tīng)它的生命周期變化而達(dá)到監(jiān)聽(tīng)到宿主Activity生命周期的目的饮六,顯然,這里是完全可行的方案苛蒲。我們先繼續(xù)分析getSupportRequestManagerFragment這個(gè)方法的實(shí)現(xiàn)卤橄。

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

這里沒(méi)有什么比較難的,唯獨(dú)就是有一個(gè)小技巧臂外,為什么需要這個(gè)pendingSupportRequestManagerFragments對(duì)象窟扑,它其實(shí)是為了避免重復(fù)創(chuàng)建SupportRequestManagerFragment對(duì)象,這里有兩個(gè)if檢查漏健,初學(xué)者可能會(huì)有點(diǎn)奇怪嚎货,這是因?yàn)镕ragmentManager提交這個(gè)方法是一個(gè)消息機(jī)制觸發(fā)的形式,并不會(huì)立即的執(zhí)行蔫浆,如果此時(shí)多次調(diào)用而沒(méi)有pendingSupportRequestManagerFragments的保證殖属,是會(huì)多次建立對(duì)象的。顯然添加到fm中后瓦盛,就不再需要pendingSupportRequestManagerFragments洗显,所以在下一個(gè)消息到達(dá)時(shí)候,ID_REMOVE_SUPPORT_FRAGMENT_MANAGER中及時(shí)的被移除原环。然后這里我們看到isParentVisible這個(gè)變量墙懂,其實(shí)是觸發(fā)Lifecycle的一些回調(diào)。有了這個(gè)Fragment之后扮念,我們繼續(xù)回到第6步的邏輯损搬。這里就開(kāi)始了RequestManager的構(gòu)造,然后再設(shè)置到SupportRequestManagerFragment的成員變量requestManager中。下面我們繼續(xù)分析這個(gè)RequestManager的構(gòu)造過(guò)程巧勤。這里factory的實(shí)現(xiàn)類是一個(gè)GeneratedRequestManagerFactory嵌灰。

8.GeneratedRequestManagerFactory#build

  @Override
  @NonNull
  public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle,
      @NonNull RequestManagerTreeNode treeNode, @NonNull Context context) {
    return new GlideRequests(glide, lifecycle, treeNode, context);
  }

這個(gè)工廠方法,最終會(huì)構(gòu)建一個(gè)GlideRequests對(duì)象颅悉,至此創(chuàng)建RequestManager的任務(wù)就已經(jīng)完成沽瞭,Glide#with方法執(zhí)行完成,這里我們可以看到剩瓶,RequestManager對(duì)于同一個(gè)上下文來(lái)說(shuō)是唯一的驹溃。下面我們繼續(xù)分析GlideRequests的load方法。

9.GlideRequests#load

  @Override
  @NonNull
  @CheckResult
  public GlideRequest<Drawable> load(@Nullable String string) {
    return (GlideRequest<Drawable>) super.load(string);
  }

這個(gè)很簡(jiǎn)單延曙,直接是調(diào)用父類的load方法豌鹤。

10.RequestManager#load

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

首先分析這個(gè)方法,發(fā)現(xiàn)返回類型是一個(gè)RequestBuilder枝缔,顯然Glide對(duì)于請(qǐng)求的各種鏈?zhǔn)浇Y(jié)構(gòu)用到了Builder的設(shè)計(jì)模式布疙,以后我們會(huì)經(jīng)常看到各種鏈?zhǔn)降亩鄥?shù)的加載方式愿卸。下面我們繼續(xù)分析asDrawable的實(shí)現(xiàn)灵临。

11.RequestManager#asDrawable

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

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

在asDrawable方法中,繼續(xù)調(diào)用了as方法趴荸,傳入了一個(gè)Drawable.class參數(shù)儒溉,接著就是調(diào)用RequestBuilder的構(gòu)造方法,將參數(shù)傳入发钝。RequestBuilder中涉及到大量的圖片加載參數(shù)的設(shè)置顿涣。接下來(lái)進(jìn)入到步驟10,通過(guò)RequestBuilder#load傳入第一個(gè)參數(shù)笼平。

12.RequestBuilder#load

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

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

這個(gè)方法也很簡(jiǎn)單,只是設(shè)置了model這個(gè)屬性的值舔痪,至此寓调,load(url)方法全部結(jié)束。接下來(lái)分析最后一個(gè)重要的方法into锄码。

13.RequestBuilder#into

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

這個(gè)方法中夺英,設(shè)計(jì)到一個(gè)新的東西RequestOptions,主要涉及到圖片的展示滋捶,這里我們也暫且跳過(guò)痛悯,它有一個(gè)默認(rèn)值。transcodeClass就是我們上面?zhèn)魅氲腄rawable.class重窟,接下來(lái)分析buildImageViewTarget這個(gè)方法的實(shí)現(xiàn)载萌。

  @NonNull
  public <X> ViewTarget<ImageView, X> buildImageViewTarget(
      @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
  }

它的具體實(shí)現(xiàn)在ImageViewTargetFactory下,我們繼續(xù)看

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

可以看到這里,我們會(huì)得到一個(gè)DrawableImageViewTarget扭仁,這個(gè)target特別重要垮衷。獲取到這個(gè)對(duì)象之后,我們繼續(xù)往下分析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 = 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;
  }

前面的檢查邏輯跳過(guò)搀突,這里我們的targetListener是null,target是一個(gè)DrawableImageViewTarget對(duì)象熊泵,然后是通過(guò)buildRequest方法仰迁,創(chuàng)建了一個(gè)Request對(duì)象⊥绶郑看名字可以知道徐许,這個(gè)才是真正的請(qǐng)求,只有到into此時(shí)怯邪,才會(huì)真正的去請(qǐng)求绊寻,我們先分析這個(gè)的實(shí)現(xiàn)。

14.RequestBuilder#buildRequest

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

這個(gè)方法直接是取了requestOptions的一些信息悬秉,以及transitionOptions信息澄步,繼續(xù)往下調(diào)用。

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;
    if (errorBuilder != null) {
      errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }

    Request mainRequest =
        buildThumbnailRequestRecursive(
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions);

    if (errorRequestCoordinator == null) {
      return mainRequest;
    }

    int errorOverrideWidth = errorBuilder.requestOptions.getOverrideWidth();
    int errorOverrideHeight = errorBuilder.requestOptions.getOverrideHeight();
    if (Util.isValidDimensions(overrideWidth, overrideHeight)
        && !errorBuilder.requestOptions.isValidOverride()) {
      errorOverrideWidth = requestOptions.getOverrideWidth();
      errorOverrideHeight = requestOptions.getOverrideHeight();
    }

    Request errorRequest = errorBuilder.buildRequestRecursive(
        target,
        targetListener,
        errorRequestCoordinator,
        errorBuilder.transitionOptions,
        errorBuilder.requestOptions.getPriority(),
        errorOverrideWidth,
        errorOverrideHeight,
        errorBuilder.requestOptions);
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }

這里我們并沒(méi)有設(shè)置和泌,直接跳過(guò)村缸,所以只用管mainRequest這個(gè)構(gòu)建過(guò)程,在這里武氓,我們可以看到梯皿,Glide是支持簡(jiǎn)單的嵌套R(shí)equest邏輯的,此時(shí)我們暫且跳過(guò)县恕。然后是進(jìn)入buildThumbnailRequestRecursive方法东羹。

 private Request buildThumbnailRequestRecursive(
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      RequestOptions requestOptions) {
    if (thumbnailBuilder != null) {
      .....
      return coordinator;
    } else if (thumbSizeMultiplier != null) {
      ....
      return coordinator;
    } else {
      // Base case: no thumbnail.
      return obtainRequest(
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight);
    }
  }

這個(gè)方法的實(shí)現(xiàn)也比較長(zhǎng),這里根據(jù)我們的邏輯忠烛,并沒(méi)有設(shè)置thumbnailBuilder和thumbSizeMultiplier属提,其實(shí)要關(guān)注的就是最后一個(gè)else邏輯,這樣分析其實(shí)能讓我不受分支的影響美尸,更容易把握整體流程冤议,呆需要深入研究thumbnai這塊時(shí)候,可以繼續(xù)去挖掘师坎。下面我們繼續(xù)看沒(méi)有thumbnail時(shí)候的邏輯恕酸,obtainRequest這個(gè)方法的實(shí)現(xiàn)。

 private Request obtainRequest(
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      RequestOptions requestOptions,
      RequestCoordinator requestCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight) {
    return SingleRequest.obtain(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListener,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory());
  }

看到這個(gè)方法的名字胯陋,是不是覺(jué)得很熟悉蕊温,對(duì)袱箱,我們的Handler里面就有類似的方法,這里Glide用到了享元的一種設(shè)計(jì)模式寿弱,出于對(duì)內(nèi)存的節(jié)省犯眠。接下來(lái)繼續(xù)分析obtain的實(shí)現(xiàn)。

 public static <R> SingleRequest<R> obtain(
      Context context,
      GlideContext glideContext,
      Object model,
      Class<R> transcodeClass,
      RequestOptions requestOptions,
      int overrideWidth,
      int overrideHeight,
      Priority priority,
      Target<R> target,
      RequestListener<R> targetListener,
      RequestListener<R> requestListener,
      RequestCoordinator requestCoordinator,
      Engine engine,
      TransitionFactory<? super R> animationFactory) {
    @SuppressWarnings("unchecked") SingleRequest<R> request =
        (SingleRequest<R>) POOL.acquire();
    if (request == null) {
      request = new SingleRequest<>();
    }
    request.init(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListener,
        requestCoordinator,
        engine,
        animationFactory);
    return request;
  }

可以看到症革,先是從對(duì)象池里面去取筐咧,有則共享,減少new對(duì)象的成本噪矛。然后調(diào)用init方法量蕊,進(jìn)行一些參數(shù)設(shè)置。最后我們看到艇挨,一個(gè)request對(duì)象的創(chuàng)建也就結(jié)束了残炮。繼續(xù)回到主線,返回到步驟13缩滨,回到into方法势就,繼續(xù)往下執(zhí)行。

15.RequestBuilder.into

 private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @NonNull RequestOptions options) {
    ....
    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;
  }

接下來(lái)從target中脉漏,此時(shí)是一個(gè)DrawableImageViewTarget苞冯,獲取此時(shí)是否有正在進(jìn)行的Request請(qǐng)求,如果有侧巨,則進(jìn)行邏輯判斷舅锄,決定是否需要開(kāi)啟一個(gè)新的,還是復(fù)用之前的司忱。顯然皇忿,我們這里previous肯定是不存在的。因此需要將當(dāng)前請(qǐng)求去執(zhí)行坦仍,這里RequestManager先是清除掉這個(gè)traget鳍烁。我們看看這個(gè)clear的實(shí)現(xiàn)。

  public void clear(@Nullable final Target<?> target) {
    if (target == null) {
      return;
    }

    if (Util.isOnMainThread()) {
      untrackOrDelegate(target);
    } else {
      mainHandler.post(new Runnable() {
        @Override
        public void run() {
          clear(target);
        }
      });
    }
  }

此時(shí)我們情景在主線程繁扎,那就是直接調(diào)用到untrackOrDelegate方法幔荒。

 private void untrackOrDelegate(@NonNull Target<?> target) {
    boolean isOwnedByUs = untrack(target);
    ....
    if (!isOwnedByUs && !glide.removeFromManagers(target) && target.getRequest() != null) {
      Request request = target.getRequest();
      target.setRequest(null);
      request.clear();
    }
  }

它的實(shí)現(xiàn)也很簡(jiǎn)單,其實(shí)就是判斷當(dāng)前target上面是否有請(qǐng)求锻离,進(jìn)行一些邏輯判斷是否需要取消铺峭。這個(gè)細(xì)節(jié)我們暫且忽略墓怀。只需明白clear大致是處理了這些邏輯汽纠。清除工作完成之后,接下來(lái)就是將當(dāng)前的request請(qǐng)求設(shè)置到這個(gè)target對(duì)象之中傀履。我們簡(jiǎn)單看下這個(gè)過(guò)程虱朵,相對(duì)比較簡(jiǎn)單莉炉。

  @Override
  public void setRequest(@Nullable Request request) {
    setTag(request);
  }

    private void setTag(@Nullable Object tag) {
    if (tagId == null) {
      isTagUsedAtLeastOnce = true;
      view.setTag(tag);
    } else {
      view.setTag(tagId, tag);
    }
  }

其實(shí)就是將Request和View做了一個(gè)綁定的關(guān)系,保存在View的tag之中碴犬。這步設(shè)置完成之后絮宁,就進(jìn)入到了最后一步。track當(dāng)前請(qǐng)求服协。

16.RequestManager#track

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

TargetTracker和RequestTracker分別是對(duì)target和request做了一個(gè)管理绍昂,TargetTracker類中更加簡(jiǎn)單,有點(diǎn)類似一個(gè)擴(kuò)展的List結(jié)構(gòu)偿荷,也就是保存了由當(dāng)前RequestManager在處理的所有Target的集合窘游,而RequestTracker則是所有Request的集合。我們要著重分析下LifecycleListener和LifeCircle的用處跳纳∪淌危可以看到RequestManager、TargetTracker以及Target均實(shí)現(xiàn)了
LifecycleListener接口寺庄,RequestTracker雖然沒(méi)有直接實(shí)現(xiàn)LifecycleListener艾蓝,但內(nèi)部也是有幾個(gè)相應(yīng)的生命周期感知的方法,RequestManager的構(gòu)造方法實(shí)現(xiàn)如下斗塘。

 RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory,
      Context context) {
    this.glide = glide;
    this.lifecycle = lifecycle;
    this.treeNode = treeNode;
    this.requestTracker = requestTracker;
    this.context = context;

    connectivityMonitor =
        factory.build(
            context.getApplicationContext(),
            new RequestManagerConnectivityListener(requestTracker));

    // If we're the application level request manager, we may be created on a background thread.
    // In that case we cannot risk synchronously pausing or resuming requests, so we hack around the
    // issue by delaying adding ourselves as a lifecycle listener by posting to the main thread.
    // This should be entirely safe.
    if (Util.isOnBackgroundThread()) {
      mainHandler.post(addSelfToLifecycle);
    } else {
      lifecycle.addListener(this);
    }
    lifecycle.addListener(connectivityMonitor);

    setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());

    glide.registerRequestManager(this);
  }

可以看到赢织,真正和宿主Acytivity綁定的正是這個(gè)RequestManager對(duì)象,所有生命周期變動(dòng)也都是先通過(guò)RequestManager來(lái)進(jìn)行分發(fā)逛拱。我們可以簡(jiǎn)單看RequestManager中敌厘,onStart/onStop/onDestroy均是做了一些下發(fā)生命周期的變化,通知到相關(guān)的類朽合,比如到RequestTracker和TargetTracker俱两,由RequestTracker再操作各個(gè)Request,而由TargetTracker再去管理各個(gè)Target曹步。這樣各個(gè)部分就可以根據(jù)LifiCircle進(jìn)行相關(guān)的操作宪彩,如RequestTracker中進(jìn)行取消和啟動(dòng)Request等。至此讲婚,大致就明白了LifecycleListener和LifeCircle的作用尿孔,其實(shí)也沒(méi)有什么神秘。無(wú)非就是找到注冊(cè)的地方筹麸,和接收的對(duì)象活合。接下來(lái),我們分析最后runRequest的實(shí)現(xiàn)物赶。

17.RequestTracker#runRequest

  public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }

這個(gè)方法中白指,分為兩種情況,isPaused變量標(biāo)識(shí)界面是否處于onStop狀態(tài)酵紫,如果此時(shí)還可見(jiàn)告嘲,則直接調(diào)用request#begin方法執(zhí)行错维,否則則是加入到pendingRequests中,這里pendingRequests的作用僅僅是為了保證Request不被Gc橄唬,因?yàn)閞equests是一個(gè)WeakHashMap赋焕,如果不使用pendingRequests強(qiáng)引用緩存,那么這個(gè)請(qǐng)求就有可能被回收掉仰楚,這里是做了這樣一個(gè)處理隆判,就能保證這些request不被系統(tǒng)回收掉,同時(shí)在requests也一定存在僧界。下面我們繼續(xù)分析begin這個(gè)方法蜜氨。

@Override
  public void begin() {
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();
    if (model == null) {
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        width = overrideWidth;
        height = overrideHeight;
      }
      // Only log at more verbose log levels if the user has set a fallback drawable, because
      // fallback Drawables indicate the user expects null models occasionally.
      int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
      onLoadFailed(new GlideException("Received null model"), logLevel);
      return;
    }

    if (status == Status.RUNNING) {
      throw new IllegalArgumentException("Cannot restart a running request");
    }

    // If we're restarted after we're complete (usually via something like a notifyDataSetChanged
    // that starts an identical request into the same Target or View), we can simply use the
    // resource and size we retrieved the last time around and skip obtaining a new size, starting a
    // new load etc. This does mean that users who want to restart a load because they expect that
    // the view size has changed will need to explicitly clear the View or Target before starting
    // the new load.
    if (status == Status.COMPLETE) {
      onResourceReady(resource, DataSource.MEMORY_CACHE);
      return;
    }

    // Restarts for requests that are neither complete nor running can be treated as new requests
    // and can run again from the beginning.

    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      target.getSize(this);
    }

    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
      target.onLoadStarted(getPlaceholderDrawable());
    }
    if (IS_VERBOSE_LOGGABLE) {
      logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    }
  }

這個(gè)方法中,先是對(duì)model進(jìn)行判斷捎泻,這個(gè)model此時(shí)就是我們傳的那個(gè)url飒炎,如果為空,則直接load失敗笆豁,然后是一些狀態(tài)的檢查和一些回調(diào)方法等郎汪,接下來(lái)判斷size,如果是有效的闯狱,則觸發(fā)去真正的請(qǐng)求煞赢,否則則是設(shè)置一個(gè)回調(diào),等待view布局有size之后哄孤,再來(lái)觸發(fā)請(qǐng)求照筑,真正的請(qǐng)求其實(shí)就在onSizeReady中被得到執(zhí)行。

18.SingleRequest#onSizeReady

@Override
  public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    if (IS_VERBOSE_LOGGABLE) {
      logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
    if (status != Status.WAITING_FOR_SIZE) {
      return;
    }
    status = Status.RUNNING;

    float sizeMultiplier = requestOptions.getSizeMultiplier();
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

    if (IS_VERBOSE_LOGGABLE) {
      logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
    }
    loadStatus = engine.load(
        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);

    // This is a hack that's only useful for testing right now where loads complete synchronously
    // even though under any executor running on any thread but the main thread, the load would
    // have completed asynchronously.
    if (status != Status.RUNNING) {
      loadStatus = null;
    }
    if (IS_VERBOSE_LOGGABLE) {
      logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
  }

這個(gè)方法中,首先檢查狀態(tài)是不是在等待size,如果不是隘冲,則表明size已經(jīng)有了陌僵,下面則是更新?tīng)顟B(tài)到Status.RUNNING跑芳,進(jìn)而去調(diào)用Engine根據(jù)參數(shù),這里面包含了所有的參數(shù)信息,緩存,圖片顯示等等支鸡,然后去開(kāi)始真正請(qǐng)求,網(wǎng)絡(luò)趁窃、內(nèi)存牧挣、磁盤(pán)緩存等等。這塊的東西很復(fù)雜醒陆,暫且放一放瀑构,這塊設(shè)計(jì)到一個(gè)結(jié)果的回調(diào)。

/**
 * A callback that listens for when a resource load completes successfully or fails due to an
 * exception.
 */
public interface ResourceCallback {

  /**
   * Called when a resource is successfully loaded.
   *
   * @param resource The loaded resource.
   */
  void onResourceReady(Resource<?> resource, DataSource dataSource);

  /**
   * Called when a resource fails to load successfully.
   *
   * @param e a non-null {@link GlideException}.
   */
  void onLoadFailed(GlideException e);
}

實(shí)現(xiàn)是在SignleRequest中统求,具體代碼大家可自行分析检碗,顯然,必須要做的一件事情是告訴Target此時(shí)的加載結(jié)果码邻,再由Target去通知View做如何的展示折剃,實(shí)際上,也是這樣子實(shí)現(xiàn)的像屋。具體細(xì)節(jié)這里不展開(kāi)了怕犁。最后回到第17步,還有一個(gè)比較簡(jiǎn)單的方法Target#onLoadStarted己莺。

19.Target#onLoadStarted

  @Override
  public void onLoadStarted(@Nullable Drawable placeholder) {
    super.onLoadStarted(placeholder);
    setResourceInternal(null);
    setDrawable(placeholder);
  }

這個(gè)方法的實(shí)現(xiàn)很簡(jiǎn)單奏甫,就是為view提前設(shè)置一些狀態(tài),比如placeholder信息等等凌受,然后等待Engine后續(xù)的加載完成阵子。

至此,這一塊簡(jiǎn)單的流程就已經(jīng)介紹結(jié)束胜蛉,基本的加載流程和LifiCircle的東西想必有了一個(gè)初步的認(rèn)識(shí)挠进,從文章分析來(lái)看,最復(fù)雜的部分可能就是Engine根據(jù)參數(shù)來(lái)具體加載的過(guò)程了誊册,后續(xù)繼續(xù)分析领突。在此,ImageView上面就已經(jīng)能夠正常的顯示出圖片了案怯。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末君旦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嘲碱,更是在濱河造成了極大的恐慌金砍,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件麦锯,死亡現(xiàn)場(chǎng)離奇詭異捞魁,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)离咐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門谱俭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人宵蛀,你說(shuō)我怎么就攤上這事昆著。” “怎么了术陶?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵凑懂,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我梧宫,道長(zhǎng)接谨,這世上最難降的妖魔是什么摆碉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮脓豪,結(jié)果婚禮上巷帝,老公的妹妹穿的比我還像新娘。我一直安慰自己扫夜,他們只是感情好楞泼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著笤闯,像睡著了一般堕阔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上颗味,一...
    開(kāi)封第一講書(shū)人閱讀 51,708評(píng)論 1 305
  • 那天超陆,我揣著相機(jī)與錄音,去河邊找鬼浦马。 笑死侥猬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的捐韩。 我是一名探鬼主播退唠,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼荤胁!你這毒婦竟也來(lái)了瞧预?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤仅政,失蹤者是張志新(化名)和其女友劉穎垢油,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體圆丹,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡滩愁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辫封。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片硝枉。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖倦微,靈堂內(nèi)的尸體忽然破棺而出妻味,到底是詐尸還是另有隱情,我是刑警寧澤欣福,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布责球,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏雏逾。R本人自食惡果不足惜嘉裤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望栖博。 院中可真熱鬧屑宠,春花似錦、人聲如沸笛匙。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)妹孙。三九已至,卻和暖如春获枝,著一層夾襖步出監(jiān)牢的瞬間蠢正,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工省店, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嚣崭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓懦傍,卻偏偏與公主長(zhǎng)得像雹舀,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子粗俱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容