Gilde的源碼學(xué)習(xí)

在大多數(shù)的時候使用Gilde只用一行代碼:

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

對于源碼學(xué)習(xí)拼缝,一開始喜歡逐行逐句的去看喇闸,后來發(fā)現(xiàn)自己非常容易陷入其中,其實(shí)只需要我們從常用的功能點(diǎn)入手去分析,明白主題邏輯就夠了
本文是基于4.0.0學(xué)習(xí)分析的

第一個方法with()
這是Gilde類提供的一組靜態(tài)方法杈帐,有多個重載的方法

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

  /**
   * Begin a load with Glide that will be tied to the given {@link android.app.Activity}'s lifecycle
   * and that uses the given {@link Activity}'s default options.
   *
   * @param activity The activity to use.
   * @return A RequestManager for the given activity that can be used to start a load.
   */
  public static RequestManager with(Activity activity) {
    return getRetriever(activity).get(activity);
  }

  /**
   * Begin a load with Glide that will tied to the give
   * {@link android.support.v4.app.FragmentActivity}'s lifecycle and that uses the given
   * {@link android.support.v4.app.FragmentActivity}'s default options.
   *
   * @param activity The activity to use.
   * @return A RequestManager for the given FragmentActivity that can be used to start a load.
   */
  public static RequestManager with(FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }

  /**
   * Begin a load with Glide that will be tied to the given {@link android.app.Fragment}'s lifecycle
   * and that uses the given {@link android.app.Fragment}'s default options.
   *
   * @param fragment The fragment to use.
   * @return A RequestManager for the given Fragment that can be used to start a load.
   */
  public static RequestManager with(android.app.Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }

  /**
   * Begin a load with Glide that will be tied to the given
   * {@link android.support.v4.app.Fragment}'s lifecycle and that uses the given
   * {@link android.support.v4.app.Fragment}'s default options.
   *
   * @param fragment The fragment to use.
   * @return A RequestManager for the given Fragment that can be used to start a load.
   */
  public static RequestManager with(Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }

可以看到重載的種類非常多,參數(shù)可以傳入Context专钉,Activity挑童,fragment,fragmentActivity等跃须,方法也是很簡單:getRetriever()獲取了RequestManagerRetriever對象站叼,再通過get()方法獲取了RequestManager ()對象,
下面分析一下getRetriever()方法干了什么

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實(shí)例并去獲取RequestManagerRetriever實(shí)例
接下來再來分析一下RequestManagerRetriever的get()方法干了啥

 public RequestManager get(Context context) {                                                                      
   if (context == null) {                                                                                          
     throw new IllegalArgumentException("You cannot start a load on a null Context");                              
   } else if (Util.isOnMainThread() && !(context instanceof Application)) {                                        
     if (context instanceof FragmentActivity) {                                                                    
       return get((FragmentActivity) context);                                                                     
     } else if (context instanceof Activity) {                                                                     
       return get((Activity) context);                                                                             
     } else if (context instanceof ContextWrapper) {                                                               
       return get(((ContextWrapper) context).getBaseContext());                                                    
     }                                                                                                             
   }                                                                                                               
                                                                                                                   
   return getApplicationManager(context);                                                                          
 }                                                                                                                 
                                                                                                                   
 public RequestManager get(FragmentActivity activity) {                                                            
   if (Util.isOnBackgroundThread()) {                                                                              
     return get(activity.getApplicationContext());                                                                 
   } else {                                                                                                        
     assertNotDestroyed(activity);                                                                                 
     FragmentManager fm = activity.getSupportFragmentManager();                                                    
     return supportFragmentGet(activity, fm, null /*parentHint*/);                                                 
   }                                                                                                               
 }                                                                                                                 
                                                                                                                   
 public RequestManager get(Fragment fragment) {                                                                    
   Preconditions.checkNotNull(fragment.getActivity(),                                                              
         "You cannot start a load on a fragment before it is attached or after it is destroyed");                  
   if (Util.isOnBackgroundThread()) {                                                                              
     return get(fragment.getActivity().getApplicationContext());                                                   
   } else {                                                                                                        
     FragmentManager fm = fragment.getChildFragmentManager();                                                      
     return supportFragmentGet(fragment.getActivity(), fm, fragment);                                              
   }                                                                                                               
 }                                                                                                                 
                                                                                                                   
 public RequestManager get(Activity activity) {                                                                    
   if (Util.isOnBackgroundThread()) {                                                                              
     return get(activity.getApplicationContext());                                                                 
   } else {                                                                                                        
     assertNotDestroyed(activity);                                                                                 
     android.app.FragmentManager fm = activity.getFragmentManager();                                               
     return fragmentGet(activity, fm, null /*parentHint*/);                                                        
   }                                                                                                               
 }                                                                                                                 
                                                                                                                   
 public RequestManager get(View view) {                                                                            
   if (Util.isOnBackgroundThread()) {                                                                              
     return get(view.getContext().getApplicationContext());                                                        
   }                                                                                                               

可以看到這也是一組重載方法,看上去有好多個參數(shù)第练,實(shí)際上只要分清楚是Application和非Application就行阔馋,
我們先看Application的情況,如果在Glide.with()方法中傳入的是一個Application對象娇掏,那么這里就會調(diào)用帶有Context參數(shù)的get()方法重載呕寝,然后getApplicationManager()方法來獲取一個RequestManager對象。其實(shí)這是最簡單的一種情況婴梧,因?yàn)锳pplication對象的生命周期即應(yīng)用程序的生命周期下梢,因此Glide并不需要做什么特殊的處理,它自動就是和應(yīng)用程序的生命周期是同步的塞蹭,如果應(yīng)用程序關(guān)閉的話孽江,Glide的加載也會同時終止。
接下來我們看傳入非Application參數(shù)的情況番电。不管你在Glide.with()方法中傳入的是Activity竟坛、FragmentActivity永丝、v4包下的Fragment、還是app包下的Fragment垦巴,最終的流程都是一樣的明也,那就是會向當(dāng)前的Activity當(dāng)中添加一個隱藏的沒有視圖的Fragment,通過與fragment的生命周期進(jìn)行關(guān)聯(lián)進(jìn)而實(shí)現(xiàn)組件的生命周期的實(shí)現(xiàn)崭歧,
另外如果我們是在非主線程當(dāng)中使用的Glide隅很,那么不管你是傳入的Activity還是Fragment,都會被強(qiáng)制當(dāng)成Application來處理
總結(jié):
Glide:初始化各個組件的使用入口
RequestManagerRetriever
是用來創(chuàng)建并從activity和fragment中檢索已存在的RequestManager率碾;
RequestManagerFragment
沒有視圖的fragment叔营,簡單的來講,就是在每一個Activity或者Fragment上又添加了一個Fragment所宰,該Fragment沒有View绒尊,僅僅用來存儲RequestManager并管理Glide請求
Request Manager
通過 ActivityFragmentLifecycle 的 addListener 方法注冊 LifecycleListener。當(dāng) RequestManagerFragment 生命周期方法執(zhí)行的時候仔粥,觸發(fā) ActivityFragmentLifecycle 的相應(yīng)方法婴谱,然后會遍歷所有注冊的 LifecycleListener 并執(zhí)行相應(yīng)生命周期方法。這樣就完成了生命周期和Glide的request請求的完整關(guān)聯(lián)躯泰。

總體來說谭羔,第一個with()方法的源碼還是比較好理解的。其實(shí)就是為了得到一個RequestManager對象而已麦向,然后Glide會根據(jù)我們傳入with()方法的參數(shù)來確定圖片加載的生命周期

第二個方法load()
由于with方法返回的是一個RequestManager的對象瘟裸,接下來的這個方法肯定是在RequestManager類中,只有一個方法诵竭,與3.7.0不同沒有那么多的重載方法:

 public RequestBuilder<Drawable> load(@Nullable Object model) {
    return asDrawable().load(model);
  }

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

創(chuàng)建一個RequestBuilder话告,并添加一個過場動畫

 public RequestBuilder<TranscodeType> load(@Nullable Object model) {
    return loadGeneric(model);
  }

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

這一步?jīng)]有什么內(nèi)容,都是在給requestBuilder參數(shù)賦值卵慰,并返回一個對象為下一步做準(zhǔn)備

第三個方法into()
with返回的是RequestManger的對象
load返回的是RequestBuilder的對象
into返回的是Target的對象

public Target<TranscodeType> into(ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      if (requestOptions.isLocked()) {
        requestOptions = requestOptions.clone();
      }
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions.optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions.optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions.optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions.optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.
      }
    }

    return into(context.buildImageViewTarget(view, transcodeClass));

首先Util.assertMainThread();判斷是否是在主線程沙郭,如果不是拋出異常,
然后Preconditions.checkNotNull(view);判斷view是否為空呵燕,若為空則拋出異常棠绘,通過判斷view的scaleType設(shè)置圖片的加載形式

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

這里其實(shí)又是調(diào)用了ImageViewTargetFactory的buildTarget()方法,我們繼續(xù)跟進(jìn)去再扭,代碼如下所示:

public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
    if (Bitmap.class.equals(clazz)) {
      return (Target<Z>) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
      return (Target<Z>) new DrawableImageViewTarget(view);
    } else {
      throw new IllegalArgumentException(
          "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
  }

可以看到氧苍,在buildTarget()方法中會根據(jù)傳入的class參數(shù)來構(gòu)建不同的Target對象,這個class參數(shù)其實(shí)基本上只有兩種情況泛范,如果你在使用Glide加載圖片的時候調(diào)用了asBitmap()方法让虐,那么這里就會構(gòu)建出BitmapImageViewTarget對象,否則的話構(gòu)建的都是GlideDrawableImageViewTarget對象罢荡,我們使用的事asDrawable

public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    Request previous = target.getRequest();

    if (previous != null) {
      requestManager.clear(target);
    }

    requestOptions.lock();
    Request request = buildRequest(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
  }

再次檢查是否是在主線程赡突,以及view是否為空对扶,并且通過isModelSet標(biāo)記判斷l(xiāng)oad
和into的先后順序,我們關(guān)注核心代碼惭缰,buildRequest構(gòu)建了request對象浪南,Request是用來發(fā)出加載圖片請求的,它是Glide中非常關(guān)鍵的一個組件漱受。我們先來看buildRequest()方法是如何構(gòu)建Request對象的:

 private Request buildRequest(Target<TranscodeType> target) {
    return buildRequestRecursive(target, null, transitionOptions, requestOptions.getPriority(),
        requestOptions.getOverrideWidth(), requestOptions.getOverrideHeight());
  }

內(nèi)部又調(diào)用了

 private Request buildRequestRecursive(Target<TranscodeType> target,
      @Nullable ThumbnailRequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority, int overrideWidth, int overrideHeight) {
    if (thumbnailBuilder != null) {
      // Recursive case: contains a potentially recursive thumbnail request builder.
      if (isThumbnailBuilt) {
        throw new IllegalStateException("You cannot use a request as both the main request and a "
            + "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
      }

      TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
          thumbnailBuilder.transitionOptions;
      if (DEFAULT_ANIMATION_OPTIONS.equals(thumbTransitionOptions)) {
        thumbTransitionOptions = transitionOptions;
      }

      Priority thumbPriority = thumbnailBuilder.requestOptions.isPrioritySet()
          ? thumbnailBuilder.requestOptions.getPriority() : getThumbnailPriority(priority);

      int thumbOverrideWidth = thumbnailBuilder.requestOptions.getOverrideWidth();
      int thumbOverrideHeight = thumbnailBuilder.requestOptions.getOverrideHeight();
      if (Util.isValidDimensions(overrideWidth, overrideHeight)
          && !thumbnailBuilder.requestOptions.isValidOverride()) {
        thumbOverrideWidth = requestOptions.getOverrideWidth();
        thumbOverrideHeight = requestOptions.getOverrideHeight();
      }

      ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
      Request fullRequest = obtainRequest(target, requestOptions, coordinator,
          transitionOptions, priority, overrideWidth, overrideHeight);
      isThumbnailBuilt = true;
      // Recursively generate thumbnail requests.
      Request thumbRequest = thumbnailBuilder.buildRequestRecursive(target, coordinator,
          thumbTransitionOptions, thumbPriority, thumbOverrideWidth, thumbOverrideHeight);
      isThumbnailBuilt = false;
      coordinator.setRequests(fullRequest, thumbRequest);
      return coordinator;
    } else if (thumbSizeMultiplier != null) {
      // Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
      ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
      Request fullRequest = obtainRequest(target, requestOptions, coordinator, transitionOptions,
          priority, overrideWidth, overrideHeight);
      RequestOptions thumbnailOptions = requestOptions.clone()
          .sizeMultiplier(thumbSizeMultiplier);

      Request thumbnailRequest = obtainRequest(target, thumbnailOptions, coordinator,
          transitionOptions, getThumbnailPriority(priority), overrideWidth, overrideHeight);

      coordinator.setRequests(fullRequest, thumbnailRequest);
      return coordinator;
    } else {
      // Base case: no thumbnail.
      return obtainRequest(target, requestOptions, parentCoordinator, transitionOptions, priority,
          overrideWidth, overrideHeight);
    }
  }

大篇幅寫的是如何處理縮略圖的络凿,我們關(guān)心這個方法obtainRequest

private Request obtainRequest(Target<TranscodeType> target,
      RequestOptions requestOptions, RequestCoordinator requestCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority,
      int overrideWidth, int overrideHeight) {
    requestOptions.lock();

    return SingleRequest.obtain(
        context,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        requestListener,
        requestCoordinator,
        context.getEngine(),
        transitionOptions.getTransitionFactory());
  }

在這里調(diào)用了SingleRequest的obtain方法,這么多參數(shù)昂羡,是不是把之前所有用到的api都添加到這個request中去了

 public static <R> SingleRequest<R> obtain(
      GlideContext glideContext,
      Object model,
      Class<R> transcodeClass,
      RequestOptions requestOptions,
      int overrideWidth,
      int overrideHeight,
      Priority priority,
      Target<R> target,
      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(
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        requestListener,
        requestCoordinator,
        engine,
        animationFactory);
    return request;
  }
private void init(
      GlideContext glideContext,
      Object model,
      Class<R> transcodeClass,
      RequestOptions requestOptions,
      int overrideWidth,
      int overrideHeight,
      Priority priority,
      Target<R> target,
      RequestListener<R> requestListener,
      RequestCoordinator requestCoordinator,
      Engine engine,
      TransitionFactory<? super R> animationFactory) {
    this.glideContext = glideContext;
    this.model = model;
    this.transcodeClass = transcodeClass;
    this.requestOptions = requestOptions;
    this.overrideWidth = overrideWidth;
    this.overrideHeight = overrideHeight;
    this.priority = priority;
    this.target = target;
    this.requestListener = requestListener;
    this.requestCoordinator = requestCoordinator;
    this.engine = engine;
    this.animationFactory = animationFactory;
    status = Status.PENDING;
  }

new 了一個SingleRequest對象絮记,這個類是Request的實(shí)現(xiàn)類,下邊的init實(shí)際上是對這些參數(shù)賦值虐先,至此解決了創(chuàng)建request的問題怨愤,那么是怎么執(zhí)行的呢
回到最還是into方法

Request request = buildRequest(target);
target.setRequest(request);
requestManager.track(target, request);

看看track方法

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

這里涉及到TargetTracker這個類,是對目標(biāo)view的生命周期進(jìn)行跟蹤管理的輔助類
接下來看runRequest這個方法

 public void runRequest(Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      pendingRequests.add(request);
    }
  }

這個RequestTracker類是對request進(jìn)行隊(duì)列管理的類蛹批,當(dāng)請求不是暫停時請求開始撰洗,先不考慮暫停又開始的情況,由于上面分析了SingleRequest是Request的實(shí)現(xiàn)類般眉,那么就去那看

public void begin() {
    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;
    }

    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 (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    }
  }

當(dāng)model==null時也就是load中傳入的為空時我們看這個方法 onLoadFailed

private void onLoadFailed(GlideException e, int maxLogLevel) {
    stateVerifier.throwIfRecycled();
    int logLevel = glideContext.getLogLevel();
    if (logLevel <= maxLogLevel) {
      Log.w(GLIDE_TAG, "Load failed for " + model + " with size [" + width + "x" + height + "]", e);
      if (logLevel <= Log.INFO) {
        e.logRootCauses(GLIDE_TAG);
      }
    }

    loadStatus = null;
    status = Status.FAILED;
    //TODO: what if this is a thumbnail request?
    if (requestListener == null
        || !requestListener.onLoadFailed(e, model, target, isFirstReadyResource())) {
      setErrorPlaceholder();
    }
  }

執(zhí)行了setErrorPlaceholder方法

private void setErrorPlaceholder() {
    if (!canNotifyStatusChanged()) {
      return;
    }

    Drawable error = null;
    if (model == null) {
      error = getFallbackDrawable();
    }
    // Either the model isn't null, or there was no fallback drawable set.
    if (error == null) {
      error = getErrorDrawable();
    }
    // The model isn't null, no fallback drawable was set or no error drawable was set.
    if (error == null) {
      error = getPlaceholderDrawable();
    }
    target.onLoadFailed(error);
  }

下面看一下getFallbackDrawable方法了赵,是干什么的

 private Drawable getFallbackDrawable() {
    if (fallbackDrawable == null) {
      fallbackDrawable = requestOptions.getFallbackDrawable();
      if (fallbackDrawable == null && requestOptions.getFallbackId() > 0) {
        fallbackDrawable = loadDrawable(requestOptions.getFallbackId());
      }
    }
    return fallbackDrawable;
  }

public final Drawable getFallbackDrawable() {
    return fallbackDrawable;
  }

  /**
   * Sets an {@link Drawable} to display if the model provided to
   * {@link com.bumptech.glide.RequestBuilder#load(Object)} is {@code null}.
   *
   * <p> If a fallback is not set, null models will cause the error drawable to be displayed. If the
   * error drawable is not set, the placeholder will be displayed.
   *
   * @see #placeholder(Drawable)
   * @see #placeholder(int)
   *
   * @param drawable The drawable to display as a placeholder.
   * @return This request builder.
   */
  public RequestOptions fallback(Drawable drawable) {
    if (isAutoCloneEnabled) {
      return clone().fallback(drawable);
    }

    this.fallbackDrawable = drawable;
    fields |= FALLBACK;

    return selfOrThrowIfLocked();
  }

這里寫的很明白了潜支,當(dāng)load的參數(shù)為空的時展示一個占位圖片甸赃,如果這個圖片沒有設(shè)置,就設(shè)置一個錯誤圖片冗酿,如果錯誤圖片都沒設(shè)置的話只能設(shè)置一個loading圖
下面看看target.onLoadFailed(error);這個方法干了什么:

/**
 * A lifecycle callback that is called when a load fails.
 *
 * <p> Note - This may be called before {@link #onLoadStarted(android.graphics.drawable.Drawable)
 * } if the model object is null.
 *
 * <p>You must ensure that any current Drawable received in {@link #onResourceReady(Object,
 * Transition)} is no longer displayed before redrawing the container (usually a View) or
 * changing its visibility.
 *
 * @param errorDrawable The error drawable to optionally show, or null.
 */
void onLoadFailed(@Nullable Drawable errorDrawable);

這是個接口埠对,看看具體實(shí)現(xiàn)

/**
   * Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
   * android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
   *
   * @param errorDrawable {@inheritDoc}
   */
  @Override
  public void onLoadFailed(@Nullable Drawable errorDrawable) {
    super.onLoadFailed(errorDrawable);
    setResourceInternal(null);
    setDrawable(errorDrawable);
  }

 @Override
  public void setDrawable(Drawable drawable) {
    view.setImageDrawable(drawable);
  }

這里可以看到,因?yàn)槌霈F(xiàn)了 異常無法正常過的加載圖片裁替,具體的為view設(shè)置了圖片项玛,至于是什么圖片則是給的什么接什么,讓我們回到begin方法();
target.onLoadStarted()圖片請求開始之前弱判,會先使用這張占位圖代替最終的圖片顯示,這也就是placeholder和error的底層實(shí)現(xiàn)原理
我們看看這個方法里邊是什么

 /**
   * Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
   * android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
   *
   * @param placeholder {@inheritDoc}
   */
  @Override
  public void onLoadStarted(@Nullable Drawable placeholder) {
    super.onLoadStarted(placeholder);
    setResourceInternal(null);
    setDrawable(placeholder);
  }
  /**
   * Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
   * android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
   *
   * @param drawable {@inheritDoc}
   */
  @Override
  public void setDrawable(Drawable drawable) {
    view.setImageDrawable(drawable);
  }

知道了占位圖的實(shí)現(xiàn)襟沮,那么 圖片加載是從哪開始的呢,在begin方法里

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

判斷了下你是否指定了一個固定的寬高昌腰,不管你是否設(shè)置了寬高都會走這個方法

/**
   * A callback method that should never be invoked directly.
   */
  @Override
  public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      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 (Log.isLoggable(TAG, Log.VERBOSE)) {
      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.getOptions(),
        requestOptions.isMemoryCacheable(),
        requestOptions.getUseUnlimitedSourceGeneratorsPool(),
        requestOptions.getOnlyRetrieveFromCache(),
        this);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
  }

從這開始涉及engine我們先看這個類是干嘛的


/**
 * Responsible for starting loads and managing active and cached resources.
 * 負(fù)責(zé)啟動加載和管理活動和緩存資源开伏。
 */
public class Engine implements EngineJobListener,
    MemoryCache.ResourceRemovedListener,
    EngineResource.ResourceListener {


/**
   * Starts a load for the given arguments. Must be called on the main thread.
   *
   * <p> The flow for any request is as follows: <ul> <li>Check the memory cache and provide the
   * cached resource if present</li> <li>Check the current put of actively used resources and return
   * the active resource if present</li> <li>Check the current put of in progress loads and add the
   * cb to the in progress load if present</li> <li>Start a new load</li> </ul> </p>
   *
   * <p> Active resources are those that have been provided to at least one request and have not yet
   * been released. Once all consumers of a resource have released that resource, the resource then
   * goes to cache. If the resource is ever returned to a new consumer from cache, it is re-added to
   * the active resources. If the resource is evicted from the cache, its resources are recycled and
   * re-used if possible and the resource is discarded. There is no strict requirement that
   * consumers release their resources so active resources are held weakly. </p>
   *
   * @param width  The target width in pixels of the desired resource.
   * @param height The target height in pixels of the desired resource.
   * @param cb     The callback that will be called when the load completes.
   */
  public <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb) {
    Util.assertMainThread();
    long startTime = LogTime.getLogTime();

    //EngineKey 的介紹是An in memory only cache key used to multiplex loads.
    //內(nèi)存中只緩存用于復(fù)用的鍵。所以這個key記錄了一次加載的各種信息
    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);
  
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }

    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }
    //這個應(yīng)該也屬于內(nèi)存緩存遭商,這里避免了EngineJob的重復(fù)創(chuàng)建固灵,EngineJob代表從硬盤緩存或者網(wǎng)絡(luò)上加載圖片并進(jìn)行decode的整個過程。
    EngineJob<?> current = jobs.get(key);
    if (current != null) {
      current.addCallback(cb);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }

    EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable,
        useUnlimitedSourceExecutorPool);
    DecodeJob<R> decodeJob = decodeJobFactory.build(
        glideContext,
        model,
        key,
        signature,
        width,
        height,
        resourceClass,
        transcodeClass,
        priority,
        diskCacheStrategy,
        transformations,
        isTransformationRequired,
        onlyRetrieveFromCache,
        options,
        engineJob);
    jobs.put(key, engineJob);
    engineJob.addCallback(cb);
    engineJob.start(decodeJob);

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
  }

這個方法有點(diǎn)長劫流,我們慢慢看
從這就開始涉及Glide的緩存機(jī)制
EngineKey 這個類是用產(chǎn)生一個用于進(jìn)行緩存的Key巫玻,決定key的因素特別多丛忆,這個類通過重寫了equals()和hashCode()方法,保證只有傳入EngineKey的所有參數(shù)都相同的情況下才認(rèn)為是同一個EngineKey對象

接下來看loadFromCache方法

private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
      return null;
    }

    EngineResource<?> cached = getEngineResourceFromCache(key);
    if (cached != null) {
      cached.acquire();
      activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
    }
    return cached;
  }  

 private EngineResource<?> getEngineResourceFromCache(Key key) {
    Resource<?> cached = cache.remove(key);

    final EngineResource<?> result;
    if (cached == null) {
      result = null;
    } else if (cached instanceof EngineResource) {
      // Save an object allocation if we've cached an EngineResource (the typical case).
      result = (EngineResource<?>) cached;
    } else {
      result = new EngineResource<>(cached, true /*isMemoryCacheable*/);
    }
    return result;
  }


 private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
      return null;
    }

    EngineResource<?> active = null;
    WeakReference<EngineResource<?>> activeRef = activeResources.get(key);
    if (activeRef != null) {
      active = activeRef.get();
      if (active != null) {
        active.acquire();
      } else {
        activeResources.remove(key);
      }
    }

    return active;
  }

為什么要判斷isMemoryCacheable 呢是因?yàn)镚lide自動幫我們開啟了緩存如果想關(guān)閉這功能只需要在skipMemoryCache()方法傳入true仍秤,那么在這里就是false熄诡,表示內(nèi)存被禁用,接著調(diào)用了getEngineResourceFromCache()方法來獲取緩存诗力。在這個方法中粮彤,會使用緩存Key來從cache當(dāng)中取值,而這里的cache對象就是在構(gòu)建Glide對象時創(chuàng)建的LruResourceCache姜骡,那么說明這里其實(shí)使用的就是LruCache算法了导坟,當(dāng)我們從LruResourceCache中獲取到緩存圖片之后會將它從緩存中移除,然后在將這個緩存圖片存儲到activeResources當(dāng)中圈澈。activeResources就是一個弱引用的HashMap惫周,用來緩存正在使用中的圖片,我們可以看到康栈,loadFromActiveResources()方法就是從activeResources這個HashMap當(dāng)中取值的递递。使用activeResources來緩存正在使用中的圖片,可以保護(hù)這些圖片不會被LruCache算法回收掉啥么,如果有的話就直接在這獲取登舞,沒有的話就開啟線程去加載圖片,接下來又進(jìn)行了內(nèi)存緩存的判斷這里避免了EngineJob的重復(fù)創(chuàng)建,EngineJob代表從硬盤緩存或者網(wǎng)絡(luò)上加載圖片并進(jìn)行decode的整個過程悬荣。

那么怎么開啟的線程又是如何加載的呢:

EngineJob的職責(zé)是調(diào)度DecodeJob菠秒,添加,移除資源回調(diào)氯迂,并notify回調(diào)践叠。DecodeJob負(fù)責(zé)從緩存資源或者原始數(shù)據(jù)中讀取資源,Glide中的臟累活基本都是這個DecodeJob干的

先從engineJob.start去看

 public void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }

利用線程池執(zhí)行decodeJob嚼蚀,那么decodeJob又有什么貓膩
decodeJob中實(shí)現(xiàn)了Runnable看一下run方法

@Override
  public void run() {
    // This should be much more fine grained, but since Java's thread pool implementation silently
    // swallows all otherwise fatal exceptions, this will at least make it obvious to developers
    // that something is failing.
    TraceCompat.beginSection("DecodeJob#run");
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      runWrapped();
    } catch (RuntimeException e) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "DecodeJob threw unexpectedly"
            + ", isCancelled: " + isCancelled
            + ", stage: " + stage, e);
      }
      // When we're encoding we've already notified our callback and it isn't safe to do so again.
      if (stage != Stage.ENCODE) {
        notifyFailed();
      }
      if (!isCancelled) {
        throw e;
      }
    } finally {
      if (currentFetcher != null) {
        currentFetcher.cleanup();
      }
      TraceCompat.endSection();
    }
  }

貌似所有的邏輯處理都在runWrapped這個方法中

 private void runWrapped() {
     switch (runReason) {
      case INITIALIZE:
        stage = getNextStage(Stage.INITIALIZE);
        currentGenerator = getNextGenerator();
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }

private DataFetcherGenerator getNextGenerator() {
    switch (stage) {
      case RESOURCE_CACHE:
        return new ResourceCacheGenerator(decodeHelper, this);
      case DATA_CACHE:
        return new DataCacheGenerator(decodeHelper, this);
      case SOURCE:
        return new SourceGenerator(decodeHelper, this);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized stage: " + stage);
    }
  }

private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    while (!isCancelled && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

      if (stage == Stage.SOURCE) {
        reschedule();
        return;
      }
    }
    // We've run out of stages and generators, give up.
    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
      notifyFailed();
    }

    // Otherwise a generator started a new load and we expect to be called back in
    // onDataFetcherReady.
  }

因?yàn)閞unReason的默認(rèn)值是INITIALIZE禁灼,首先調(diào)用getNextStage方法獲取到stage值,然后執(zhí)行g(shù)etNextGenerator根據(jù)stage不同的值獲取相應(yīng)的generator
一共有幾種generators
ResourceCacheGenerator:從處理過的緩存加載數(shù)據(jù)
DataCacheGenerator:從原始緩存加載數(shù)據(jù)
SourceGenerator:從數(shù)據(jù)源請求數(shù)據(jù)

最后執(zhí)行runGeneratores轿曙,currentGenerator.startNext()
點(diǎn)進(jìn)去看到時候發(fā)現(xiàn)有3個
分別是:
DataCacheGenerator
ResourceCacheGenerator
SourceGenerator
這里主要看一下SourceGenerator的方法

 @Override
  public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }

    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
      return true;
    }
    sourceCacheGenerator = null;

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

接下來我們看loadData方法

/**
 * A DataFetcher that retrieves an {@link java.io.InputStream} for a Url.
 */
public class HttpUrlFetcher implements DataFetcher<InputStream> {
  @Override
  public void loadData(Priority priority, DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    final InputStream result;
    try {
      result = loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/,
          glideUrl.getHeaders());
    } catch (IOException e) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "Failed to load data for url", e);
      }
      callback.onLoadFailed(e);
      return;
    }
  if (Log.isLoggable(TAG, Log.VERBOSE)) {
      Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime)
          + " ms and loaded " + result);
    }
    callback.onDataReady(result);
}

 private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
      Map<String, String> headers) throws IOException {
    if (redirects >= MAXIMUM_REDIRECTS) {
      throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
    } else {
      // Comparing the URLs using .equals performs additional network I/O and is generally broken.
      // See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
      try {
        if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
          throw new HttpException("In re-direct loop");

        }
      } catch (URISyntaxException e) {
        // Do nothing, this is best effort.
      }
    }

    urlConnection = connectionFactory.build(url);
    for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
      urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
    }
    urlConnection.setConnectTimeout(timeout);
    urlConnection.setReadTimeout(timeout);
    urlConnection.setUseCaches(false);
    urlConnection.setDoInput(true);

    // Stop the urlConnection instance of HttpUrlConnection from following redirects so that
    // redirects will be handled by recursive calls to this method, loadDataWithRedirects.
    urlConnection.setInstanceFollowRedirects(false);

    // Connect explicitly to avoid errors in decoders if connection fails.
    urlConnection.connect();
    if (isCancelled) {
      return null;
    }
    final int statusCode = urlConnection.getResponseCode();
    if (statusCode / 100 == 2) {
      return getStreamForSuccessfulRequest(urlConnection);
    } else if (statusCode / 100 == 3) {
      String redirectUrlString = urlConnection.getHeaderField("Location");
      if (TextUtils.isEmpty(redirectUrlString)) {
        throw new HttpException("Received empty or null redirect url");
      }
      URL redirectUrl = new URL(url, redirectUrlString);
      return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
    } else if (statusCode == -1) {
      throw new HttpException(statusCode);
    } else {
      throw new HttpException(urlConnection.getResponseMessage(), statusCode);
    }
  }
)
private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
      throws IOException {
    if (TextUtils.isEmpty(urlConnection.getContentEncoding())) {
      int contentLength = urlConnection.getContentLength();
      stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength);
    } else {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "Got non empty content encoding: " + urlConnection.getContentEncoding());
      }
      stream = urlConnection.getInputStream();
    }
    return stream;
  }

到這我們是找到了網(wǎng)絡(luò)通訊的代碼了弄捕,通過網(wǎng)絡(luò)下載獲取到inputStream,然后把流給callback.onDataReady(result);
我們再看代碼:SourceGenerator

 @Override
  public void onDataReady(Object data) {
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
    if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      dataToCache = data;
      // We might be being called back on someone else's thread. Before doing anything, we should
      // reschedule to get back onto Glide's thread.
      cb.reschedule();
    } else {
      cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
          loadData.fetcher.getDataSource(), originalKey);
    }
  }

最后回調(diào)到decodejob的方法

@Override
  public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
      DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;
    this.currentData = data;
    this.currentFetcher = fetcher;
    this.currentDataSource = dataSource;
    this.currentAttemptingKey = attemptedKey;
    if (Thread.currentThread() != currentThread) {
      runReason = RunReason.DECODE_DATA;
      callback.reschedule(this);
    } else {
      TraceCompat.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        decodeFromRetrievedData();
      } finally {
        TraceCompat.endSection();
      }
    }
  }

private void decodeFromRetrievedData() {
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logWithTimeAndKey("Retrieved data", startFetchTime,
          "data: " + currentData
          + ", cache key: " + currentSourceKey
          + ", fetcher: " + currentFetcher);
    }
    Resource<R> resource = null;
    try {
      //把數(shù)據(jù)流編碼成resource類型
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      exceptions.add(e);
    }
    if (resource != null) {
      //將resource返回
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }

private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
    if (resource instanceof Initializable) {
      ((Initializable) resource).initialize();
    }
    Resource<R> result = resource;
    LockedResource<R> lockedResource = null;
    if (deferredEncodeManager.hasResourceToEncode()) {
      lockedResource = LockedResource.obtain(resource);
      result = lockedResource;
    }

    notifyComplete(result, dataSource);

    stage = Stage.ENCODE;
    try {
      if (deferredEncodeManager.hasResourceToEncode()) {
        deferredEncodeManager.encode(diskCacheProvider, options);
      }
    } finally {
      if (lockedResource != null) {
        lockedResource.unlock();
      }
      onEncodeComplete();
    }
  }


private void notifyComplete(Resource<R> resource, DataSource dataSource) {
    setNotifiedOrThrow();
    callback.onResourceReady(resource, dataSource);
  }

最終把數(shù)據(jù)回調(diào)到onResourceReady

 @Override
  public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    this.resource = resource;
    this.dataSource = dataSource;
    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
  }

之后發(fā)送了一條消息

private static class MainThreadCallback implements Handler.Callback {

    @Synthetic
    MainThreadCallback() { }

    @Override
    public boolean handleMessage(Message message) {
      EngineJob<?> job = (EngineJob<?>) message.obj;
      switch (message.what) {
        case MSG_COMPLETE:
          job.handleResultOnMainThread();
          break;
        case MSG_EXCEPTION:
          job.handleExceptionOnMainThread();
          break;
        case MSG_CANCELLED:
          job.handleCancelledOnMainThread();
          break;
        default:
          throw new IllegalStateException("Unrecognized message: " + message.what);
      }
      return true;
    }
  }

@Synthetic
  void handleResultOnMainThread() {
    stateVerifier.throwIfRecycled();
    if (isCancelled) {
      resource.recycle();
      release(false /*isRemovedFromQueue*/);
      return;
    } else if (cbs.isEmpty()) {
      throw new IllegalStateException("Received a resource without any callbacks to notify");
    } else if (hasResource) {
      throw new IllegalStateException("Already have resource");
    }
    engineResource = engineResourceFactory.build(resource, isCacheable);
    hasResource = true;

    // Hold on to resource for duration of request so we don't recycle it in the middle of
    // notifying if it synchronously released by one of the callbacks.
    engineResource.acquire();
    listener.onEngineJobComplete(key, engineResource);

    for (ResourceCallback cb : cbs) {
      if (!isInIgnoredCallbacks(cb)) {
        engineResource.acquire();
        cb.onResourceReady(engineResource, dataSource);
      }
    }
    // Our request is complete, so we can release the resource.
    engineResource.release();

    release(false /*isRemovedFromQueue*/);
  }

之后回調(diào)到SingleRequest

 @SuppressWarnings("unchecked")
  @Override
  public void onResourceReady(Resource<?> resource, DataSource dataSource) {
    stateVerifier.throwIfRecycled();
    loadStatus = null;
    if (resource == null) {
      GlideException exception = new GlideException("Expected to receive a Resource<R> with an "
          + "object of " + transcodeClass + " inside, but instead got null.");
      onLoadFailed(exception);
      return;
    }

    Object received = resource.get();
    if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
      releaseResource(resource);
      GlideException exception = new GlideException("Expected to receive an object of "
          + transcodeClass + " but instead" + " got "
          + (received != null ? received.getClass() : "") + "{" + received + "} inside" + " "
          + "Resource{" + resource + "}."
          + (received != null ? "" : " " + "To indicate failure return a null Resource "
          + "object, rather than a Resource object containing null data."));
      onLoadFailed(exception);
      return;
    }

    if (!canSetResource()) {
      releaseResource(resource);
      // We can't put the status to complete before asking canSetResource().
      status = Status.COMPLETE;
      return;
    }

    onResourceReady((Resource<R>) resource, (R) received, dataSource);
  }

 private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
    // We must call isFirstReadyResource before setting status.
    boolean isFirstResource = isFirstReadyResource();
    status = Status.COMPLETE;
    this.resource = resource;

    if (glideContext.getLogLevel() <= Log.DEBUG) {
      Log.d(GLIDE_TAG, "Finished loading " + result.getClass().getSimpleName() + " from "
          + dataSource + " for " + model + " with size [" + width + "x" + height + "] in "
          + LogTime.getElapsedMillis(startTime) + " ms");
    }

    if (requestListener == null
        || !requestListener.onResourceReady(result, model, target, dataSource, isFirstResource)) {
      Transition<? super R> animation =
          animationFactory.build(dataSource, isFirstResource);
      target.onResourceReady(result, animation);
    }

    notifyLoadSuccess();
  }

最后我們看 target.onResourceReady(result, animation);這個方法
點(diǎn)進(jìn)去一看

public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>
    implements Transition.ViewAdapter {
    @Override
  public void onResourceReady(Z resource, @Nullable Transition<? super Z> transition) {
    if (transition == null || !transition.transition(resource, this)) {
      setResourceInternal(resource);
    } else {
      maybeUpdateAnimatable(resource);
    }
  }
}
 private void setResourceInternal(@Nullable Z resource) {
    maybeUpdateAnimatable(resource);
    setResource(resource);
  }
protected abstract void setResource(@Nullable Z resource);

至此就能把圖片顯示出來了导帝,至于如何編碼解碼的并沒有深入探討分析守谓,整體的過了一遍流程
總體來說跟3.7.0流程上還是有很大的區(qū)別的,至于沒弄的細(xì)節(jié)有時間再弄舟扎。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末分飞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子睹限,更是在濱河造成了極大的恐慌譬猫,老刑警劉巖讯檐,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異染服,居然都是意外死亡别洪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門柳刮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挖垛,“玉大人,你說我怎么就攤上這事秉颗×《荆” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵蚕甥,是天一觀的道長哪替。 經(jīng)常有香客問我,道長菇怀,這世上最難降的妖魔是什么凭舶? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮爱沟,結(jié)果婚禮上帅霜,老公的妹妹穿的比我還像新娘。我一直安慰自己呼伸,他們只是感情好身冀,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蜂大,像睡著了一般闽铐。 火紅的嫁衣襯著肌膚如雪蝶怔。 梳的紋絲不亂的頭發(fā)上奶浦,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天,我揣著相機(jī)與錄音踢星,去河邊找鬼澳叉。 笑死,一個胖子當(dāng)著我的面吹牛沐悦,可吹牛的內(nèi)容都是我干的成洗。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼藏否,長吁一口氣:“原來是場噩夢啊……” “哼瓶殃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起副签,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤遥椿,失蹤者是張志新(化名)和其女友劉穎基矮,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冠场,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡家浇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了碴裙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钢悲。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖舔株,靈堂內(nèi)的尸體忽然破棺而出莺琳,到底是詐尸還是另有隱情,我是刑警寧澤载慈,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布芦昔,位于F島的核電站,受9級特大地震影響娃肿,放射性物質(zhì)發(fā)生泄漏咕缎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一料扰、第九天 我趴在偏房一處隱蔽的房頂上張望凭豪。 院中可真熱鬧,春花似錦晒杈、人聲如沸嫂伞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帖努。三九已至,卻和暖如春粪般,著一層夾襖步出監(jiān)牢的瞬間拼余,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工亩歹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匙监,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓小作,卻偏偏與公主長得像亭姥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子顾稀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

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