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

下面來看在Glide中最簡單的圖片加載代碼

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

這應(yīng)該是相對比較簡單的加載圖片的代碼了麸恍,一步步來灵巧,看代碼其實(shí)很講究耐心,有時(shí)候會(huì)遇到很多層次的調(diào)用鏈或南,這個(gè)時(shí)候其實(shí)很有必要自己畫一些圖孩等,很能幫助理清一些思路艾君。下面來看這段比較看似比較簡單的代碼采够,其實(shí)在Glide源碼中,運(yùn)用到了大量的類的設(shè)計(jì)冰垄,后面涉及的我會(huì)慢慢介紹到蹬癌。

首先簡單介紹下這個(gè)Glide類,它相當(dāng)于是整個(gè)框架的調(diào)用入口虹茶,有一點(diǎn)像外觀模式逝薪,一般很多第三方sdk都會(huì)用到這種模式,提供一個(gè)高層接口蝴罪,減少用戶的使用成本董济,對于我們第一個(gè)with方法,這個(gè)其實(shí)就是一個(gè)工廠方法要门,雖然有許多重載的形式虏肾,其實(shí)都是要?jiǎng)?chuàng)建一個(gè)RequestManager對象。下面我們來看這個(gè)
這個(gè)with方法欢搜,如下:

icon_glide_with.png

Glide#with方法有六個(gè)重載的形式封豪,但是第一部分都是調(diào)用Glide#getRetriever獲取一個(gè)RequestManagerRetriever對象,進(jìn)而調(diào)用RequestManagerRetriever#get方法最終創(chuàng)建一個(gè)RequestManager對象炒瘟。下面一個(gè)個(gè)來進(jìn)行分析吹埠。

1.Glide#with

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

還有其他的重載形式,其實(shí)第一部分都是一樣,都是獲取他們(Actvity/View/Fragment等)的上下文缘琅,然后通過getRetriever方法去獲取一個(gè)RequestManagerRetriever對象粘都。進(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的單例對象驯杜,初始化Glide對象時(shí),做了很多復(fù)雜的配置信息做个,包括緩存策略等等鸽心,這里我們暫時(shí)跳過,后續(xù)講到這些配置信息再詳細(xì)分析居暖,有時(shí)候顽频,看代碼要忽略其他的細(xì)節(jié),沿著一條主線走太闺,站在宏觀的視角糯景,針對具體問題再行微觀分析,往往會(huì)比較清晰省骂。這里獲取到一個(gè)Glide實(shí)例之后蟀淮,回到第2步,接下來回到Glide#getRetriever钞澳,然后是調(diào)用了Glide#getRequestManagerRetriever繼續(xù)請求怠惶。

4.Glide#getRequestManagerRetriever

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

這個(gè)方法很簡單,就是返回一個(gè)RequestManagerRetriever對象轧粟,那么它是在什么時(shí)候初始化的呢策治,通過代碼分析,在Glide初始化時(shí)候兰吟,會(huì)初始化這個(gè)requestManagerRetriever對象通惫,我們暫且略過它。有了這個(gè)requestManagerRetriever對象后混蔼,回到第1步履腋,接下來會(huì)調(diào)用RequestManagerRetriever#get方法,與Glide#with對應(yīng)惭嚣,它也有6個(gè)重載的形式遵湖,均是返回一個(gè)RequestManager。

5.RequestManagerRetriever#get

icon_request_manager_retriever_get.png

雖然是有這么多重載形式料按,但都是一個(gè)平行的關(guā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ù)再來分析一些分支的情況√颖矗可以看到谣辞,在ui線程中,首先是獲取了support下面的FragmentManager對象沐扳,然后繼續(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è)道理杨拐,我們可以假定某一種情況祈餐,便于代碼的主線分析。接下來是構(gòu)建了一個(gè)SupportRequestManagerFragment對象哄陶,它就是一個(gè)Fragment對象帆阳,其實(shí)沒有什么神秘,它里面綁定了一些Lifecycle的方法奕筐,后續(xù)我們會(huì)看到舱痘。這里其實(shí)用了一個(gè)技巧,因?yàn)槲覀兛吹嚼牒眨櫼粋€(gè)Activity的生命周期,同時(shí)又要能夠達(dá)到通用性塌碌,顯然在用戶的業(yè)務(wù)Activity中是不太可能能插入生命周期的鉤子方法渊胸,那么,作為一個(gè)框架層面的台妆,顯然要必備一些通用性才行翎猛,這里Glide是通過手動(dòng)添加一個(gè)隱藏的SupportRequestManagerFragment對象,通過監(jiān)聽它的生命周期變化而達(dá)到監(jiān)聽到宿主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;
  }

這里沒有什么比較難的疫稿,唯獨(dú)就是有一個(gè)小技巧,為什么需要這個(gè)pendingSupportRequestManagerFragments對象,它其實(shí)是為了避免重復(fù)創(chuàng)建SupportRequestManagerFragment對象遗座,這里有兩個(gè)if檢查舀凛,初學(xué)者可能會(huì)有點(diǎn)奇怪,這是因?yàn)镕ragmentManager提交這個(gè)方法是一個(gè)消息機(jī)制觸發(fā)的形式途蒋,并不會(huì)立即的執(zhí)行猛遍,如果此時(shí)多次調(diào)用而沒有pendingSupportRequestManagerFragments的保證,是會(huì)多次建立對象的号坡。顯然添加到fm中后懊烤,就不再需要pendingSupportRequestManagerFragments,所以在下一個(gè)消息到達(dá)時(shí)候宽堆,ID_REMOVE_SUPPORT_FRAGMENT_MANAGER中及時(shí)的被移除奸晴。然后這里我們看到isParentVisible這個(gè)變量,其實(shí)是觸發(fā)Lifecycle的一些回調(diào)日麸。有了這個(gè)Fragment之后寄啼,我們繼續(xù)回到第6步的邏輯。這里就開始了RequestManager的構(gòu)造代箭,然后再設(shè)置到SupportRequestManagerFragment的成員變量requestManager中墩划。下面我們繼續(xù)分析這個(gè)RequestManager的構(gòu)造過程。這里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對象,至此創(chuàng)建RequestManager的任務(wù)就已經(jīng)完成极景,Glide#with方法執(zhí)行完成察净,這里我們可以看到,RequestManager對于同一個(gè)上下文來說是唯一的盼樟。下面我們繼續(xù)分析GlideRequests的load方法氢卡。

9.GlideRequests#load

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

這個(gè)很簡單,直接是調(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對于請求的各種鏈?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è)置。接下來進(jìn)入到步驟10与境,通過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è)方法也很簡單,只是設(shè)置了model這個(gè)屬性的值摔刁,至此挥转,load(url)方法全部結(jié)束。接下來分析最后一個(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,主要涉及到圖片的展示拗引,這里我們也暫且跳過借宵,它有一個(gè)默認(rèn)值。transcodeClass就是我們上面?zhèn)魅氲腄rawable.class矾削,接下來分析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è)對象之后断部,我們繼續(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;
  }

前面的檢查邏輯跳過,這里我們的targetListener是null蝴光,target是一個(gè)DrawableImageViewTarget對象她渴,然后是通過buildRequest方法,創(chuàng)建了一個(gè)Request對象蔑祟〕煤模看名字可以知道,這個(gè)才是真正的請求做瞪,只有到into此時(shí)对粪,才會(huì)真正的去請求,我們先分析這個(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;
  }

這里我們并沒有設(shè)置,直接跳過乳蛾,所以只用管mainRequest這個(gè)構(gòu)建過程暗赶,在這里鄙币,我們可以看到,Glide是支持簡單的嵌套R(shí)equest邏輯的蹂随,此時(shí)我們暫且跳過十嘿。然后是進(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)也比較長岳锁,這里根據(jù)我們的邏輯绩衷,并沒有設(shè)置thumbnailBuilder和thumbSizeMultiplier,其實(shí)要關(guān)注的就是最后一個(gè)else邏輯激率,這樣分析其實(shí)能讓我不受分支的影響咳燕,更容易把握整體流程,呆需要深入研究thumbnai這塊時(shí)候乒躺,可以繼續(xù)去挖掘招盲。下面我們繼續(xù)看沒有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è)方法的名字曹货,是不是覺得很熟悉,對讳推,我們的Handler里面就有類似的方法顶籽,這里Glide用到了享元的一種設(shè)計(jì)模式,出于對內(nèi)存的節(jié)省娜遵。接下來繼續(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;
  }

可以看到,先是從對象池里面去取设拟,有則共享慨仿,減少new對象的成本。然后調(diào)用init方法纳胧,進(jìn)行一些參數(shù)設(shè)置镰吆。最后我們看到,一個(gè)request對象的創(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;
  }

接下來從target中,此時(shí)是一個(gè)DrawableImageViewTarget芝雪,獲取此時(shí)是否有正在進(jìn)行的Request請求减余,如果有,則進(jìn)行邏輯判斷惩系,決定是否需要開啟一個(gè)新的位岔,還是復(fù)用之前的如筛。顯然,我們這里previous肯定是不存在的抒抬。因此需要將當(dā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)也很簡單抓于,其實(shí)就是判斷當(dāng)前target上面是否有請求做粤,進(jìn)行一些邏輯判斷是否需要取消。這個(gè)細(xì)節(jié)我們暫且忽略捉撮。只需明白clear大致是處理了這些邏輯怕品。清除工作完成之后,接下來就是將當(dāng)前的request請求設(shè)置到這個(gè)target對象之中巾遭。我們簡單看下這個(gè)過程肉康,相對比較簡單。

  @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)前請求炫乓。

16.RequestManager#track

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

TargetTracker和RequestTracker分別是對target和request做了一個(gè)管理,TargetTracker類中更加簡單献丑,有點(diǎn)類似一個(gè)擴(kuò)展的List結(jié)構(gòu)末捣,也就是保存了由當(dāng)前RequestManager在處理的所有Target的集合,而RequestTracker則是所有Request的集合创橄。我們要著重分析下LifecycleListener和LifeCircle的用處箩做。可以看到RequestManager妥畏、TargetTracker以及Target均實(shí)現(xiàn)了
LifecycleListener接口邦邦,RequestTracker雖然沒有直接實(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對象网棍,所有生命周期變動(dòng)也都是先通過RequestManager來進(jìn)行分發(fā)郭赐。我們可以簡單看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í)也沒有什么神秘倒得。無非就是找到注冊的地方泻红,和接收的對象。接下來霞掺,我們分析最后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í)還可見,則直接調(diào)用request#begin方法執(zhí)行骗灶,否則則是加入到pendingRequests中惨恭,這里pendingRequests的作用僅僅是為了保證Request不被Gc,因?yàn)閞equests是一個(gè)WeakHashMap耙旦,如果不使用pendingRequests強(qiáng)引用緩存脱羡,那么這個(gè)請求就有可能被回收掉,這里是做了這樣一個(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è)方法中氓鄙,先是對model進(jìn)行判斷,這個(gè)model此時(shí)就是我們傳的那個(gè)url业舍,如果為空抖拦,則直接load失敗,然后是一些狀態(tài)的檢查和一些回調(diào)方法等舷暮,接下來判斷size态罪,如果是有效的,則觸發(fā)去真正的請求下面,否則則是設(shè)置一個(gè)回調(diào)复颈,等待view布局有size之后,再來觸發(fā)請求沥割,真正的請求其實(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ài)到Status.RUNNING,進(jìn)而去調(diào)用Engine根據(jù)參數(shù)似将,這里面包含了所有的參數(shù)信息获黔,緩存,圖片顯示等等在验,然后去開始真正請求玷氏,網(wǎng)絡(luò)、內(nèi)存腋舌、磁盤緩存等等盏触。這塊的東西很復(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é)這里不展開了来破。最后回到第17步篮灼,還有一個(gè)比較簡單的方法Target#onLoadStarted。

19.Target#onLoadStarted

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

這個(gè)方法的實(shí)現(xiàn)很簡單徘禁,就是為view提前設(shè)置一些狀態(tài)诅诱,比如placeholder信息等等,然后等待Engine后續(xù)的加載完成送朱。

至此娘荡,這一塊簡單的流程就已經(jīng)介紹結(jié)束,基本的加載流程和LifiCircle的東西想必有了一個(gè)初步的認(rèn)識(shí)驶沼,從文章分析來看炮沐,最復(fù)雜的部分可能就是Engine根據(jù)參數(shù)來具體加載的過程了,后續(xù)繼續(xù)分析回怜。在此大年,ImageView上面就已經(jīng)能夠正常的顯示出圖片了。

下一篇 Glide源碼分析(二),基本加載類圖介紹

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末翔试,一起剝皮案震驚了整個(gè)濱河市轻要,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌遏餐,老刑警劉巖伦腐,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異失都,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)幸冻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門粹庞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人洽损,你說我怎么就攤上這事庞溜。” “怎么了碑定?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵流码,是天一觀的道長。 經(jīng)常有香客問我延刘,道長漫试,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任碘赖,我火速辦了婚禮驾荣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘普泡。我一直安慰自己播掷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布撼班。 她就那樣靜靜地躺著歧匈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪砰嘁。 梳的紋絲不亂的頭發(fā)上件炉,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機(jī)與錄音般码,去河邊找鬼妻率。 笑死,一個(gè)胖子當(dāng)著我的面吹牛板祝,可吹牛的內(nèi)容都是我干的宫静。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼孤里!你這毒婦竟也來了伏伯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤捌袜,失蹤者是張志新(化名)和其女友劉穎说搅,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體虏等,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡弄唧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了霍衫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片候引。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖敦跌,靈堂內(nèi)的尸體忽然破棺而出澄干,到底是詐尸還是另有隱情,我是刑警寧澤柠傍,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布麸俘,位于F島的核電站,受9級(jí)特大地震影響惧笛,放射性物質(zhì)發(fā)生泄漏从媚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一徐紧、第九天 我趴在偏房一處隱蔽的房頂上張望静檬。 院中可真熱鬧,春花似錦并级、人聲如沸拂檩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽稻励。三九已至,卻和暖如春愈涩,著一層夾襖步出監(jiān)牢的瞬間望抽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工履婉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留煤篙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓毁腿,卻偏偏與公主長得像辑奈,于是被迫代替她去往敵國和親苛茂。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

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