從源碼角度深刻理解Glide4(上)

image

談到Glide,從英文字面意思有滑行、滑動的意思;而Android從開發的角度咱們知道它是一款圖片加載框架,這裏引用官方文檔的一句話「Glide是一個快速高效的Android圖片加載庫,注重於平滑的滾動」,從官方文檔介紹咱們瞭解到用Glide框架來加載圖片是快速而且高效的,接下來就來經過簡單使用Glide和源碼理解兩個方面看看Glide是不是快速和高效(文中代碼基於Glide 4.8版本)。html

Glide簡單使用

  • 1.使用前須要添加依賴java

    implementation 'com.github.bumptech.glide:glide:4.8.0'
    //使用Generated API須要引入 
    annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
    複製代碼
  • 2.簡單加載網絡圖片到ImageView,能夠看到簡單一句代碼就能將網絡圖片加載到ImageView,也可使用Generated API方式android

    //直接使用
    Glide.with(Context).load(IMAGE_URL).into(mImageView)
    
    //使用Generated API, 做用範圍Application 模塊內使用
    //建立MyAppGlideModule類加上@GlideModule註解,make project 就能使用 GlideApp
    @GlideModule
    public final class MyAppGlideModule extends AppGlideModule {}
    
    //Generated API加載圖片
    GlideApp.with(Context).load(IMAGE_URL).into(mImageView);
    複製代碼
  • 3.當加載網絡圖片的時候,網絡請求是耗時操做,因此圖片不可能立刻就加載出來,網絡請求這段時間ImageView是空白的,因此咱們可使用一個佔位符顯示圖片來優化用戶體驗,佔位符有三種git

    • 加載佔位符(placeholder)
    • 錯誤佔位符(error)
    • 後備回調符(Fallback)
    //添加佔位圖
         RequestOptions requestOptions = new RequestOptions()
             .placeholder(R.drawable.ic_cloud_download_black_24dp)
             .error(R.drawable.ic_error_black_24dp)
             .diskCacheStrategy(DiskCacheStrategy.NONE);//不使用緩存
         Glide.with(Context).load(IMAGE_URL).apply(requestOptions).into(mImageView);
    
    //Generated API 方式(和Glide3 同樣)
    GlideApp.with(Context).load(IMAGE_URL)
             .placeholder(R.drawable.ic_cloud_download_black_24dp)
             .error(R.drawable.ic_error_black_24dp)
             .diskCacheStrategy(DiskCacheStrategy.NONE)
             .into(mImageView);
             
    // 後備回調符(Fallback) Generated API 方式纔有,在應用設置用戶頭像場景中,若是用戶不設置,也就是爲null的狀況,可使用後備回調符顯示默認頭像
    private static final String NULL_URL=null;
    GlideApp.with(Context).load(NULL_URL)
             .fallback(R.drawable.ic_account_circle_black_24dp)
             .into(mImageView);
    複製代碼
  • 4.指定加載圖片的大小(override)github

    RequestOptions requestOptions = new RequestOptions().override(200,100);
    Glide.with(Context).load(IMAGE_URL).apply(requestOptions).into(mImageView);
    
    //Generated API 方式
    GlideApp.with(Context).load(IMAGE_URL)
                 .override(200,100)
                 .into(mImageView);
    複製代碼
  • 5.縮略圖 (Thumbnail)緩存

    • 這個其實和佔位符(placeholder)有些類似,可是佔位符只能加載本地資源,而縮略圖能夠加載網絡資源,thumbnail方法與咱們的主動加載並行運行,若是主動加載已經完成,則縮略圖不會顯示
    //縮略圖Options
    RequestOptions requestOptions = new RequestOptions()
            .override(200,100)
            .diskCacheStrategy(DiskCacheStrategy.NONE);
     Glide.with(Context)
                .load(IMAGE_URL)
                .thumbnail( Glide.with(this)
                .load(IMAGE_URL)
                .apply(requestOptions))
                .into(mImageView);
    //Generated API 方式
     GlideApp.with(Context).
                load(IMAGE_URL).
                thumbnail( GlideApp.with(this)
                .load(IMAGE_URL).override(200,100)
            .diskCacheStrategy(DiskCacheStrategy.NONE)).into(mImageView);
    複製代碼
  • 6.圖像變化bash

    • Glide中內置了三種圖片的變化操做,分別是CenterCrop(圖片原圖的中心區域進行裁剪顯示),FitCenter(圖片原始長寬鋪滿)和CircleCrop(圓形裁剪)網絡

      //顯示圓形裁剪到ImageView
      RequestOptions requestOptions = new RequestOptions()
                  .circleCrop()
                  .diskCacheStrategy(DiskCacheStrategy.NONE);
      
      Glide.with(Context)
                  .load(IMAGE_URL)
                  .apply(requestOptions)
                  .into(mImageView);
                  
      //RequestOptions都內置了使用者三種變化的靜態方法
      Glide.with(Context)
                  .load(IMAGE_URL)
                  .apply(RequestOptions.circleCropTransform())
                  .into(mImageView);
                  
      //Generated API 方式
      GlideApp.with(Context).load(IMAGE_URL)
                  .circleCrop()
                  .diskCacheStrategy(DiskCacheStrategy.NONE)
                  .into(mImageView);
      
      複製代碼
    • 若是想要更酷炫的變化,可使用第三方框架glide-transformations來幫助咱們實現,而且變化是能夠組合的app

      //第三方框架glide-transformations引入
      implementation 'jp.wasabeef:glide-transformations:4.0.0'
      
      //使用glide-transformations框架 變換圖片顏色和加入模糊效果
       RequestOptions requestOptions=new RequestOptions()
                 .placeholder(R.drawable.ic_cloud_download_black_24dp)
                 .transforms(new ColorFilterTransformation(Color.argb(80, 255, 0, 0)),new BlurTransformation(30))
                 .diskCacheStrategy(DiskCacheStrategy.NONE);
        
        Glide.with(Context).load(IMAGE_URL).
                 apply(requestOptions).
                 into(mImageView);
      
        //Generated API 方式
        GlideApp.with(Context).load(IMAGE_URL)
                 .transforms(new ColorFilterTransformation(Color.argb(80, 255, 0, 0)),new BlurTransformation(30))
                 .placeholder(R.drawable.ic_cloud_download_black_24dp)
                 .diskCacheStrategy(DiskCacheStrategy.NONE)
                 .into(mImageView);
                
      複製代碼

      glide_transformation

    • 更多效果能夠查看官方例子框架

  • 7.加載目標(Target)

    • Target是介於請求和請求者之間的中介者的角色,into方法的返回值就是target對象,以前咱們一直使用的 into(ImageView) ,它實際上是一個輔助方法,它接受一個 ImageView 參數併爲其請求的資源類型包裝了一個合適的 ImageViewTarget

      //加載
      Target<Drawable> target = 
       Glide.with(Context)
      .load(url)
      .into(new Target<Drawable>() {
        ...
      });
      
      //清除加載
      Glide.with(Context).clear(target);
      複製代碼
    • 當咱們使用Notification顯示應用通知,若是想要自定義通知的界面,咱們須要用到RemoteView,若是要給RemoteView設置ImageView,根據提供的setImageViewBitmap方法,若是通知界面須要加載網絡圖片,則須要將網絡圖片轉換成bitmap,通常咱們能夠根據獲取圖片連接的流來轉換成bitmap,或者使用本文的主題使用Glide框架,這些都是耗時操做,感受操做起來很麻煩,而Glide框架很貼心的給我提供了NotificationTarget(繼承SimpleTarget),相對於咱們加載目標變成Notification

    /**
     * 新建 NotificationTarget 對象參數說明,與Glide3不一樣,Glide4的asBitmap()方法必須在load方法前面
     * @param context 上下文對象          
     * @param viewId 須要加載ImageView的view的 id        
     * @param remoteViews RemoteView對象   
     * @param notification   Notification對象
     * @param notificationId Notification Id
     */
    String iamgeUrl = "http://p1.music.126.net/fX0HfPMAHJ2L_UeJWsL7ig==/18853325881511874.jpg?param=130y130";     
     
    NotificationTarget notificationTarget = new NotificationTarget(mContext,R.id.notification_Image_play,mRemoteViews,mNotification,notifyId);
    Glide.with(mContext.getApplicationContext())
                 .asBitmap()
                 .load(iamgeUrl)
                 .into( notificationTarget );
                 
    //Generated API 方式            
    GlideApp.with(mContext.getApplicationContext())
                 .asBitmap()
                 .load(iamgeUrl)
                 .into( notificationTarget );
    複製代碼

    glide_notification

  • 8.回調監聽

    • 使用Glide加載圖片,雖然在加載中或者加失敗都有佔位符方法處理,可是咱們仍是但願能夠知道圖片究竟是加載成功仍是失敗,Glide也給咱們提供了監聽方法來知道圖片究竟是加載成功仍是失敗,結合listener和into方法來使用回調
    Glide.with(this).load(IMAGE_URL).
                  listener(new RequestListener<Drawable>() {
                      @Override
                      public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                     Toast.makeText(getApplicationContext(),"圖片加載失敗",Toast.LENGTH_SHORT).show();
                          return false;
                      }
    
                      @Override
                      public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                     Toast.makeText(getApplicationContext(),"圖片加載成功",Toast.LENGTH_SHORT).show();
                          return false;
                      }
                  }).into(mImageView);*/
          //Generated API 方式
          GlideApp.with(this).load(IMAGE_URL)
                  .listener(new RequestListener<Drawable>() {
                      @Override
                      public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                          Toast.makeText(getApplicationContext(),"圖片加載失敗",Toast.LENGTH_SHORT).show();
                          return false;
                      }
    
                      @Override
                      public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                          Toast.makeText(getApplicationContext(),"圖片加載成功",Toast.LENGTH_SHORT).show();
                          return false;
                      }
                  }).into(mImageView);
    複製代碼
    • 能夠看到監聽實現的方法都有布爾類型的返回值,返回true,則表明處理了該回調事件,false則不進行處理,若是onResourceReady方法返回true,則into方法就不會執行,也就是圖片不會加載到ImageView,同理onLoadFailed方法返回true,則error方法不會執行。

Glide還有其餘的一些使用方法,這裏就不繼續展開了,有興趣的能夠自行繼續研究。

Glide源碼解析

Glide加載圖片到ImageView基本流程圖

Glide加載基本流程圖

Glide加載圖片到ImageView源碼分析

  • 在上一節簡單的列出了一些Glide的使用方法,能用不表明你已經懂了,接下來就經過理解源碼的方式來對Glide是如何工做的作深一層次理解,首先從最簡單使用開始
Glide.with(Context).load(IMAGE_URL).into(mImageView);
複製代碼

with方法

  • 來吧,開始是Glide的with()方法,直接上源碼
/** Glide類的with()方法*/
@NonNull
  public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }

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

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

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

  @SuppressWarnings("deprecation")
  @Deprecated
  @NonNull
  public static RequestManager with(@NonNull android.app.Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }

  @NonNull
  public static RequestManager with(@NonNull View view) {
    return getRetriever(view.getContext()).get(view);
  }
複製代碼
  • 經過源碼,能夠看到with有不一樣參數類型的重載方法,每一個方法首先都是調用 getRetriever()方法
/** Glide類的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();
  }
複製代碼
  • Glide的get方法中經過new GlideBuilder()獲取了Glide對象,並經過Glide的getRequestManagerRetriever()的方法最終獲得RequestManagerRetriever對象,接下來咱們看看RequestManagerRetriever對象的get方法
/** RequestManagerRetriever類的get()方法*/
 @NonNull
  public RequestManager get(@NonNull 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);
  }

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

  @NonNull
  public RequestManager get(@NonNull 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, fragment.isVisible());
    }
  }

  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      return fragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull View view) {
    if (Util.isOnBackgroundThread()) {
      return get(view.getContext().getApplicationContext());
    }
    Preconditions.checkNotNull(view);
    Preconditions.checkNotNull(view.getContext(),
        "Unable to obtain a request manager for a view without a Context");
    Activity activity = findActivity(view.getContext());
    // The view might be somewhere else, like a service.
    if (activity == null) {
      return get(view.getContext().getApplicationContext());
    }

    // Support Fragments.
    // Although the user might have non-support Fragments attached to FragmentActivity, searching
    // for non-support Fragments is so expensive pre O and that should be rare enough that we
    // prefer to just fall back to the Activity directly.
    if (activity instanceof FragmentActivity) {
      Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
      return fragment != null ? get(fragment) : get(activity);
    }

    // Standard Fragments.
    android.app.Fragment fragment = findFragment(view, activity);
    if (fragment == null) {
      return get(activity);
    }
    return get(fragment);
  }
複製代碼
  • 一樣,RequestManagerRetriever對象的get方法也有不一樣類型參數的重載,分別針對Application、Activity、Fragmenet、view作了不一樣的處理,先看Context參數的get方法,在該方法中它把Context的參數分紅了兩個類型,一個Application類型的Context,另外一個是非Application類型的Context。若是是Application類型的Context,則建立的Glide的生命週期則跟隨ApplicationContext的生命週期,也就是下面的getApplicationManager所作的事情。
/** RequestManagerRetriever類的getApplicationManager()方法*/
  @NonNull
  private RequestManager getApplicationManager(@NonNull Context context) {
    // Either an application context or we're on a background thread. if (applicationManager == null) { synchronized (this) { if (applicationManager == null) { // Normally pause/resume is taken care of by the fragment we add to the fragment or // activity. However, in this case since the manager attached to the application will not // receive lifecycle events, we must force the manager to start resumed using // ApplicationLifecycle. // TODO(b/27524013): Factor out this Glide.get() call. Glide glide = Glide.get(context.getApplicationContext()); applicationManager = factory.build( glide, new ApplicationLifecycle(), new EmptyRequestManagerTreeNode(), context.getApplicationContext()); } } } return applicationManager; } 複製代碼
  • 接着,若是是非Application類型的,Activity、Fragmenet屬於非Application;若是是Activity類型的Context,當前再也不主線程,則繼續跟隨Application生命週期,不然給當前Activity添加一個隱藏的Fragment,而後Glide生命週期跟隨這個隱藏的Fragment,分析到這裏,咱們再看Fragmenet類型的Context,或者是View類型,也是添加了一個隱藏的Fragment。這是爲何呢?首先Fragment的生命週期是和Activity同步的,Activity銷燬Fragment也會銷燬,其次,這也方便Glide知道本身何時須要中止加載,若是咱們打開一個Activity並關閉它,若是Glide生命週期跟隨Application,則Activity雖然已經銷燬,可是應用還沒退出,則Glide還在繼續加載圖片,這顯然是不合理的,而Glide很巧妙的用一個隱藏Fragment來解決生命週期的監聽。
/** RequestManagerRetriever類的fragmentGet()方法*/
  @SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"})
  @Deprecated
  @NonNull
  private RequestManager fragmentGet(@NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }
  
  /** RequestManagerRetriever類的getRequestManagerFragment()方法*/
  @SuppressWarnings("deprecation")
  @NonNull
  private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }
複製代碼
  • 通過對into方法的分析,最終獲取的是跟隨對應Context對象生命週期的RequestManager對象

load方法

  • 通過上一小節的分析,Glide.with方法最終獲取的是RequestManager對象,因此繼續看RequestManager對象裏面load方法,
/** RequestManager 類的as()方法*/
 @NonNull
  @CheckResult
  public <ResourceType> RequestBuilder<ResourceType> as(
      @NonNull Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
  }
/** RequestManager 類的as()方法*/
 @NonNull
  @CheckResult
  public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
  }
/** RequestManager 類的部分load()方法*/
 @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
    return asDrawable().load(bitmap);
  }
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
    return asDrawable().load(drawable);
  }

  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable String string) {
    return asDrawable().load(string);
  }
  //省略其餘參數類型 load() 方法
 .......
複製代碼
  • 經過以上load方法,能夠發現雖然RequestManager對象的load方法有多個類型參數的重載,可是無論load方法傳遞什麼類型參數,該方法都是調用RequestBuilder對象的load方法
/** RequestBuilder 類的load()方法*/
 @NonNull
  @CheckResult
  @SuppressWarnings("unchecked")
  @Override
  public RequestBuilder<TranscodeType> load(@Nullable Object model) {
    return loadGeneric(model);
  }
/** RequestBuilder對象 類的loadGeneric()方法*/
  @NonNull
  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }
複製代碼
  • 經過以上RequestBuilder對象的load()方法,咱們能夠明白無論RequestManager對象的load方法方法傳遞什麼類型的加載資源參數,RequestBuilder對象都把它當作時Object對象,並在loadGeneric方法中賦值給RequestBuilder對象的model對象。
  • 經過查看RequestBuilder對象,咱們還注意到apply(RequestOptions)這個方法,前面咱們的例子中使用緩存,加載圖像大小,設置加載佔位符和錯誤佔位符都須要新建RequestOptions對象,並設置咱們的配置,如今咱們分析的加載並無apply一個RequestOptions對象,則Glide會使用requestOptions.clone()去加載默認配置,這裏就先不進行展開了,先繼續關注接下來的into方法。
/** RequestBuilder 類的apply方法*/
 @NonNull
  @CheckResult
  public RequestBuilder<TranscodeType> apply(@NonNull RequestOptions requestOptions) {
    Preconditions.checkNotNull(requestOptions);
    this.requestOptions = getMutableOptions().apply(requestOptions);
    return this;
  }
 
  @SuppressWarnings("ReferenceEquality")
  @NonNull
  protected RequestOptions getMutableOptions() {
    return defaultRequestOptions == this.requestOptions
        ? this.requestOptions.clone() : this.requestOptions;
  }
複製代碼
  • 通過以上對with()方法和load方法的分析,通過這兩步以後獲得了RequestBuilder對象,也就說明真正的圖片加載操做是在into方法來完成,也就是RequestBuilder對象的into方法。

into方法

  • 經過上一小節的分析,通過load方法以後獲取的對象是RequestBuilder,而且咱們將load方法的參數賦值給了RequestBuilder對象的model參數,接下來就到了Glide最核心的方法,也就是RequestBuilder對象的into方法
獲取DrawableImageViewTarget
/** 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);
  }
複製代碼
  • RequestBuilder 對象的into方法中首先獲取傳遞進來的ImageView的ScaleType,讓Glide加載出來的ImageView保持同樣的ScaleType變化,而後咱們看到最後一句話,該方法返回了RequestBuilder 對象的另外一個into方法,先看glideContext.buildImageViewTarget()作了什麼操做
/** GlideContext 類的 buildImageViewTarget方法*/
  @NonNull
  public <X> ViewTarget<ImageView, X> buildImageViewTarget(
      @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
  }
  public class ImageViewTargetFactory {
  @NonNull
  @SuppressWarnings("unchecked")
  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 {
      //省略代碼
      .....
    }
  }
}
複製代碼
  • 經過以上源碼,以前咱們看RequestBuilder源碼中as方法傳入的是Drawable.class,因此以上的buildImageViewTarget方法最終返回的是DrawableImageViewTarget對象,接着咱們繼續看第一步into方法返回into方法中作了什麼操做
構建Request
/** RequestBuilder 類的into方法返回的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);
    //省略部分代碼
    ......
    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);
    return target;
  }
複製代碼
  • 經過以上源碼,咱們應該先明白Request類是一個接口,他抽象了Glide加載圖片請求(Request類源碼這裏就不貼了),它是一個很是重要的類,這裏咱們先看看buildRequest(target, targetListener, options)方法是如何建立Request對象的
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);
  }
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) {
   //省略部分代碼 error Request build
    ..... 
    Request mainRequest =
        buildThumbnailRequestRecursive(
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions);

    if (errorRequestCoordinator == null) {
      return mainRequest;
    }
    //省略部分代碼 error Request build
    ..... 
  }
  
  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) {
      //省略部分代碼 縮略圖操做
    .....
    } else {
      // Base case: no thumbnail.
      return obtainRequest(
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight);
    }
  }

  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,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory());
  }
複製代碼
  • 經過上面的源碼,咱們能夠看到buildRequest方法調用了buildRequestRecursive方法,在buildRequestRecursive方法中大部分代碼都在處理縮略圖(thumbnail),咱們主流程中沒有設置縮略圖,這裏就不進行展開分析,接着buildRequestRecursive方法又調用了obtainRequest方法,obtainRequest方法傳遞了很是多參數,好比有咱們熟悉的RequestOptions,設置圖片尺寸的 overrideWidth, overrideHeight,還有第一步into方法中的target對象,也就是DrawableImageViewTarget對象,model也就是咱們load傳入的圖片地址,也就說明無論load方法仍是apply方法傳入的參數最終都給到了這裏傳入SingleRequest.obtain方法,咱們繼續看看SingleRequest類
public final class SingleRequest<R> implements Request,
    SizeReadyCallback,
    ResourceCallback,
    FactoryPools.Poolable {
//省略部分代碼
......
/**SingleRequest類的 obtain方法*/
 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,
      @Nullable List<RequestListener<R>> requestListeners,
      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,
        requestListeners,
        requestCoordinator,
        engine,
        animationFactory);
    return request;
  }
  //省略部分代碼
  ......
}  
複製代碼
  • 經過SingleRequest對象的obtain方法,咱們能夠看到request = new SingleRequest<>();也就是最終咱們構建的Request是SingleRequest對象,並在init方法中將上一步obtainRequest方法傳遞進來的各類參數進行賦值。
Request執行
  • 構建完成Request對象,接下來繼續看剛剛的into方法下面的操做
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target
複製代碼
  • 首先RequestManager對象清除target,此時不懂你是否還記得RequestManager,該對象是第一步with方法以後獲得的,接着是將咱們上一步獲得的SingleRequest對象設置給target,接着又執行了RequestManager.track方法,繼續跟進該方法看看
/** RequestManager 類的track方法*/
void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }
/** RequestTracker 類的runRequest方法*/  
private final List<Request> pendingRequests = new ArrayList<>();
 public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }  
複製代碼
  • 經過上面的源碼,RequestManager對象的track方法中執行了RequestTracker 類的runRequest方法,該方法中簡單判斷當前Glide是否在暫停狀態,不是暫停狀態則執行Request的begin方法,不然將這個Request加入到請求隊列ListpendingRequests中.
後備回調符、加載佔位符和錯誤佔位符加載
  • 接下來咱們看看Request的begin方法到底幹了啥,要找到begin方法實現,根據前面分析,咱們則應該去看SingleRequest對象的begin方法
/** SingleRequest 類的begin方法*/  
@Override
  public void begin() {
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();
    if (model == null) {
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        width = overrideWidth;
        height = overrideHeight;
      }
      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 (status == Status.COMPLETE) {
      onResourceReady(resource, DataSource.MEMORY_CACHE);
      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 (IS_VERBOSE_LOGGABLE) {
      logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    }
  }
  
  private void onLoadFailed(GlideException e, int maxLogLevel) {
      //省略部分代碼
      .......
      if (!anyListenerHandledUpdatingTarget) {
        setErrorPlaceholder();
      }
     //省略部分代碼
     ....... 
  }
複製代碼
  • 經過以上begin方法源碼,若是model爲空,也就是咱們load傳入的圖片地址爲空,則會調用onLoadFailed方法,而onLoadFailed方法又調用了setErrorPlaceholder方法,接着看看該方法中作了什麼操做
/** SingleRequest 類的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);
  }
  
  private Drawable getErrorDrawable() {
    if (errorDrawable == null) {
      errorDrawable = requestOptions.getErrorPlaceholder();
      if (errorDrawable == null && requestOptions.getErrorId() > 0) {
        errorDrawable = loadDrawable(requestOptions.getErrorId());
      }
    }
    return errorDrawable;
  }
複製代碼
  • 經過以上源碼,若是咱們傳入圖片地址爲空,則首先查看是否有後備回調符設置,而後是錯誤佔位符,最後是加載佔位符,最終調用target.onLoadFailed方法,也就是ImageViewTarget的onLoadFailed方法
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>implements Transition.ViewAdapter {
  //省略部分代碼
  .......
  public void setDrawable(Drawable drawable) {
    view.setImageDrawable(drawable);
  }
  
  @Override
  public void onLoadStarted(@Nullable Drawable placeholder) {
    super.onLoadStarted(placeholder);
    setResourceInternal(null);
    setDrawable(placeholder);
  }

  @Override
  public void onLoadFailed(@Nullable Drawable errorDrawable) {
    super.onLoadFailed(errorDrawable);
    setResourceInternal(null);
    setDrawable(errorDrawable);
  }
  //省略部分代碼
  .......
}
複製代碼
  • 經過以上源碼,我想你應該已經明白了後備回調符、錯誤佔位符加載,這裏還有一個疑問,加載佔位符呢?咱們回到以前SingleRequest對象的begin方法,相信你會立刻看到在加載狀態爲RUNNING的時候調用了target.onLoadStarted,也實現了加載中的佔位符,到這裏咱們已經分析完了後備回調符、加載佔位符和錯誤佔位符加載底層實現邏輯。
加載圖片網絡請求
  • 前面分析完各類佔位符實現,咱們再次回到SingleRequest對象的begin方法,咱們能夠注意到onSizeReady()和target.getSize()這兩句就是加載圖片的入口,若是咱們在使用glide的時候設置圖片加載的大小尺寸,則會調用target.getSize()
/** ViewTarget 類的etSize方法*/ 
void getSize(@NonNull SizeReadyCallback cb) {
      int currentWidth = getTargetWidth();
      int currentHeight = getTargetHeight();
      if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
        cb.onSizeReady(currentWidth, currentHeight);
        return;
      }
      //省略部分代碼
      ......
    }
複製代碼
  • 經過以上源碼,target.getSize()會根據ImageView的寬高來得出圖片的加載寬高,最終target.getSize()仍是會調用onSizeReady()方法,因此咱們就直接來看看SingleRequest對象onSizeReady()方法中作了什麼操做。
/** 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)); } } 複製代碼
  • 在onSizeReady方法中,主要調用了engine.load()方法並返回加載狀態,engine.load方法繼續接收咱們以前傳入的各類參數,其中也有咱們model對象,也就是以前load方法傳入的圖片地址。首先咱們須要瞭解engine是什麼,顧名思義,engine的英文意思是發動機,而在Glide框架中他就是負責啓動圖片加載的發動機,主要負責啓動加載,咱們在前面with方法獲取glide對象中獲得了engine對象(這裏就不貼源碼了),咱們接着看engine.load()方法進行什麼操做
/** Engine 類的load方法*/
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,boolean isScaleOnlyOrNoTransform,Options options,boolean isMemoryCacheable,boolean useUnlimitedSourceExecutorPool,boolean useAnimationPool,boolean onlyRetrieveFromCache,ResourceCallback cb) {
    Util.assertMainThread();
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);

    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
      current.addCallback(cb);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }

    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);

    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);

    jobs.put(key, engineJob);

    engineJob.addCallback(cb);
    engineJob.start(decodeJob);

    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
  }
/**  DecodeJob 類的繼承關係*/  
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
    Runnable,
    Comparable<DecodeJob<?>>,
    Poolable   
複製代碼
  • 經過以上源碼,Engine對象的load方前面一段代碼都是在處理緩存問題,這裏先不進行展開,繼續走咱們加載圖片的主線,往下看咱們看到構建了一個EngineJob對象,還構建了一個DecodeJob對象,構建DecodeJob對象又繼續接收咱們以前傳入的各類參數,由DecodeJob對象的繼承關係咱們能夠知道它是Runnable對象,接着咱們看到engineJob的start()方法,它直接傳入了DecodeJob對象
/** EngineJob 類的start方法*/
public void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }
/** GlideExecutor 類的newSourceExecutor方法*/  
public static GlideExecutor newSourceExecutor(
      int threadCount, String name, UncaughtThrowableStrategy uncaughtThrowableStrategy) {
    return new GlideExecutor(
        new ThreadPoolExecutor(
            threadCount /* corePoolSize */,
            threadCount /* maximumPoolSize */,
            0 /* keepAliveTime */,
            TimeUnit.MILLISECONDS,
            new PriorityBlockingQueue<Runnable>(),
            new DefaultThreadFactory(name, uncaughtThrowableStrategy, false)));
  }  
複製代碼
  • 經過以上源碼,EngineJob對象的start方法首先仍是判斷緩存,最終獲取的GlideExecutor就是一個線程池執行器(Executor),GlideExecutor中有各類方法得到緩存線程池,還有資源線程池(SourceExecutor),以上源碼貼出資源線程池。實際上EngineJob對象的start方法就是用來在線程池中啓動DecodeJob這個Runnable對象,也就是說EngineJob的主要做用是開啓線程來加載圖片,接着咱們來看看DecodeJob對象的run方法。
/** DecodeJob 類的run方法*/
public void run() {
    DataFetcher<?> localFetcher = currentFetcher;
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      runWrapped();
    } catch (Throwable t) {
      //省略部分代碼
      .......
    } finally {
      if (localFetcher != null) {
        localFetcher.cleanup();
      }
      GlideTrace.endSection();
    }
  }
/** DecodeJob 類的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);
    }
  }
/** DecodeJob 類的getNextStage方法*/   
private Stage getNextStage(Stage current) {
    switch (current) {
      case INITIALIZE:
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
      case RESOURCE_CACHE:
        return diskCacheStrategy.decodeCachedData()
            ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
      case DATA_CACHE:
        // Skip loading from source if the user opted to only retrieve the resource from cache.
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
  }
 /** DecodeJob 類的getNextGenerator方法*/   
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);
    }
 /** DecodeJob 類的runGenerators方法*/       
 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;
      }
    }
   //省略部分代碼
      ....... 
  }    
複製代碼
  • 上面咱們再次貼出了一堆代碼,咱們來好好梳理一下邏輯,DecodeJob對象的run方法中邏輯很簡單,就是調用了自身的runWrapped方法,runWrapped方法中首先判斷Stage枚舉,前面在建立DecodeJob對象時候設置初始狀態爲Stage.INITIALIZE,而後接着調用getNextStage方法,這裏咱們仍是繼續跳過緩存,因此getNextStage方法最終返回的是Stage.SOURCE狀態,接着在getNextGenerator()方法中咱們獲取就是SourceGenerator對象,也就是run方法中的第一句話DataFetcher<?> localFetcher = currentFetcher中localFetcher就是咱們剛剛得到的SourceGenerator對象,接着繼續執行runGenerators()方法,在該方法的while循環判斷條件執行了currentGenerator.startNext()方法,也就是SourceGenerator對象的startNext()方法
/** SourceGenerator 類的startNext()方法*/ 
@Override
  public boolean startNext() {
    //省略部分代碼,跳過緩存部分判斷
    ........
    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;
  }
/** DecodeHelper 類的getLoadData() 方法*/
List<LoadData<?>> getLoadData() {
    if (!isLoadDataSet) {
      isLoadDataSet = true;
      loadData.clear();
      List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
      //noinspection ForLoopReplaceableByForEach to improve perf
      for (int i = 0, size = modelLoaders.size(); i < size; i++) {
        ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
        LoadData<?> current =
            modelLoader.buildLoadData(model, width, height, options);
        if (current != null) {
          loadData.add(current);
        }
      }
    }
    return loadData;
  }
/** HttpGlideUrlLoader 類的buildLoadData 方法*/ 
 @Override
  public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,
      @NonNull Options options) {
    // GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time
    // spent parsing urls.
    GlideUrl url = model;
    if (modelCache != null) {
      url = modelCache.get(model, 0, 0);
      if (url == null) {
        modelCache.put(model, 0, 0, model);
        url = model;
      }
    }
    int timeout = options.get(TIMEOUT);
    return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
  } 
複製代碼
  • 經過上面源碼,咱們接着看到loadData=helper.getLoadData().get(loadDataListIndex++)這一句代碼,helper就是DecodeHelper對象,在咱們前面建立DecodeJob對象的時候已經把它建立,以前咱們在load步驟中傳入的model是圖片url地址,因此通過DecodeHelper 類的getLoadData() 方法(更細的代碼這裏就不進行展開了),最終獲取的ModelLoader<Object, ?> modelLoader對象則爲HttpGlideUrlLoader對象,也就是laodData對象,因此modelLoader.buildLoadData建立則在HttpGlideUrlLoader對象的buildLoadData中實現,上方貼出的該方法源碼中把咱們model賦值給GlideUrl對象,也就是將其做爲URL地址來進行處理,則通過modelLoader.buildLoadData獲取的loadData.fetcher則對應HttpUrlFetcher對象,因此loadData.fetcher.loadData調用的就是HttpUrlFetcher對象loadData方法,
/**HttpUrlFetcher類的loadData方法 **/
@Override
  public void loadData(@NonNull Priority priority,
      @NonNull DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    try {
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
      callback.onDataReady(result);
    } catch (IOException e) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "Failed to load data for url", e);
      }
      callback.onLoadFailed(e);
    } finally {
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
      }
    }
  }
/**HttpUrlFetcher類的loadDataWithRedirects方法 **/  
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();
    // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352. stream = urlConnection.getInputStream(); if (isCancelled) { return null; } final int statusCode = urlConnection.getResponseCode(); if (isHttpOk(statusCode)) { return getStreamForSuccessfulRequest(urlConnection); } else if (isHttpRedirect(statusCode)) { String redirectUrlString = urlConnection.getHeaderField("Location"); if (TextUtils.isEmpty(redirectUrlString)) { throw new HttpException("Received empty or null redirect url"); } URL redirectUrl = new URL(url, redirectUrlString); // Closing the stream specifically is required to avoid leaking ResponseBodys in addition // to disconnecting the url connection below. See #2352. cleanup(); return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers); } else if (statusCode == INVALID_STATUS_CODE) { throw new HttpException(statusCode); } else { throw new HttpException(urlConnection.getResponseMessage(), statusCode); } } 複製代碼
  • 經過以上源碼,HttpUrlFetcher對象的loadData方法首先調用自身loadDataWithRedirects方法,接着咱們看到該方法源碼,這裏使用了HttpURLConnection來執行了網絡請求,看到這裏心裏仍是有點開心的,前面看了這麼多源碼,終於看到Glide的網絡請求了,開心以後還沒完呢,還得接着往下看,執行完網絡請求成功,loadDataWithRedirects方法中網絡請求成功調用getStreamForSuccessfulRequest返回了一個InputStream流(記住這個InputStream,很關鍵),而後執行了一個callback回調,而這個回調對象就是咱們以前在SourceGenerator對象中調用loadData方法傳入SourceGenerator對象自己,因此callback.onDataReady()調用的就是SourceGenerator對象的onDataReady方法
/**SourceGenerator類的onDataReady方法 **/  
  @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);
    }
  }
複製代碼
  • 經過以上源碼,不走緩存的狀況下則調用cb.onDataFetcherReady,這個cb也就是前面咱們new SourceGenerator對象傳入的 DecodeJob對象,也就是調用DecodeJob對象onDataFetcherReady方法
/**DecodeJob類的onDataFetcherReady方法 **/ 
 @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 {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        decodeFromRetrievedData();
      } finally {
        GlideTrace.endSection();
      }
    }
  }
複製代碼
  • 經過以上源碼,onDataFetcherReady方法中將以前網絡請求獲得的流賦值給當前的DecodeJob對象的currentData,其餘數據都賦值給對應字段,最終調用的是decodeFromRetrievedData方法
加載圖片(解碼,轉碼)
/**DecodeJob類的decodeFromRetrievedData方法 **/ 
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 {
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }
/**DecodeJob類的decodeFromData方法 **/   
private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data,
      DataSource dataSource) throws GlideException {
    try {
      if (data == null) {
        return null;
      }
      long startTime = LogTime.getLogTime();
      Resource<R> result = decodeFromFetcher(data, dataSource);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Decoded result " + result, startTime);
      }
      return result;
    } finally {
      fetcher.cleanup();
    }
  }
/**DecodeJob類的decodeFromFetcher方法 **/  
 private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
      throws GlideException {
    LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
    return runLoadPath(data, dataSource, path);
  }
複製代碼
  • 經過以上源碼,decodeFromRetrievedData方法調用了decodeFromFetcher方法,在該方法中首先經過decodeHelper.getLoadPath獲取LoadPath對象,LoadPath對象實際上是根據咱們傳入的處理數據來返回特定的數據解碼轉碼處理器,咱們跟進decodeHelper.getLoadPath看看
/** DecodeHelper類的getLoadPath方法*/
<Data> LoadPath<Data, ?, Transcode> getLoadPath(Class<Data> dataClass) {
    return glideContext.getRegistry().getLoadPath(dataClass, resourceClass, transcodeClass);
  }
/** Registry類的getLoadPath方法*/
 @Nullable
  public <Data, TResource, Transcode> LoadPath<Data, TResource, Transcode> getLoadPath(
      @NonNull Class<Data> dataClass, @NonNull Class<TResource> resourceClass,
      @NonNull Class<Transcode> transcodeClass) {
    //省略部分代碼
    .......
     List<DecodePath<Data, TResource, Transcode>> decodePaths =
          getDecodePaths(dataClass, resourceClass, transcodeClass);
      if (decodePaths.isEmpty()) {
        result = null;
      } else {
        result =
            new LoadPath<>(
                dataClass, resourceClass, transcodeClass, decodePaths, throwableListPool);
      }
      loadPathCache.put(dataClass, resourceClass, transcodeClass, result);
    }
    return result;
  } 
/** Registry類的getDecodePaths方法*/ 
@NonNull
  private <Data, TResource, Transcode> List<DecodePath<Data, TResource, Transcode>> getDecodePaths(
      @NonNull Class<Data> dataClass, @NonNull Class<TResource> resourceClass,
      @NonNull Class<Transcode> transcodeClass) {
      //省略部分代碼,去除干擾

        List<ResourceDecoder<Data, TResource>> decoders =
            decoderRegistry.getDecoders(dataClass, registeredResourceClass);
        ResourceTranscoder<TResource, Transcode> transcoder =
            transcoderRegistry.get(registeredResourceClass, registeredTranscodeClass);
        @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
        DecodePath<Data, TResource, Transcode> path =
            new DecodePath<>(dataClass, registeredResourceClass, registeredTranscodeClass,
                decoders, transcoder, throwableListPool);
        decodePaths.add(path);
    }
    return decodePaths;
  }
 /** Registry類的getDecoders方法*/  
 public synchronized <T, R> List<ResourceDecoder<T, R>> getDecoders(@NonNull Class<T> dataClass,
      @NonNull Class<R> resourceClass) {
    List<ResourceDecoder<T, R>> result = new ArrayList<>();
    for (String bucket : bucketPriorityList) {
      List<Entry<?, ?>> entries = decoders.get(bucket);
      if (entries == null) {
        continue;
      }
      for (Entry<?, ?> entry : entries) {
        if (entry.handles(dataClass, resourceClass)) {
          result.add((ResourceDecoder<T, R>) entry.decoder);
        }
      }
    }
    // TODO: cache result list.

    return result;
  } 
複製代碼
  • 經過以上源碼,咱們接着前面跟進DecodeHelper.getLoadPath方法,它調用了Registry對象的getLoadPath方法,Registry對象的getLoadPath方法又調用了自身的getDecodePaths方法,如今我前面提到過得咱們網絡請求獲取的是InputStream流,因此上面源碼getDecodePaths方法中Data泛型就是InputStream,在根據getDecoders方法遍歷獲得解碼器ResourceDecoder能處理InputStream流的有StreamBitmapDecoder和StreamGifDecoder,StreamGifDecoder處理的是Gif,咱們這裏處理圖片就之能是StreamBitmapDecoder,它將InputStream流解碼成bitmap,而後能將bitmap轉換成Drawable的轉碼器ResourceTranscoder對象則是BitmapDrawableTranscoder,最後getDecodePaths將咱們剛剛分析獲得的解碼器和轉碼器傳遞給了新建的DecodePath對象,DecodePath對象就是用來幫助咱們進行解碼和轉碼的。
  • 接着咱們繼續上一步的decodeFromFetcher方法,該方法返回的runLoadPath最終調用了上面得到的DecodePath對象的decode方法
/**DecodePath類的decode方法**/
public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
      @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
    Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
    Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
    return transcoder.transcode(transformed, options);
  }
/**DecodePath類的decodeResource方法**/
@NonNull
  private Resource<ResourceType> decodeResource(DataRewinder<DataType> rewinder, int width,
      int height, @NonNull Options options) throws GlideException {
    List<Throwable> exceptions = Preconditions.checkNotNull(listPool.acquire());
    try {
      return decodeResourceWithList(rewinder, width, height, options, exceptions);
    } finally {
      listPool.release(exceptions);
    }
  }
/**DecodePath類的decodeResourceWithList方法**/
  @NonNull
  private Resource<ResourceType> decodeResourceWithList(DataRewinder<DataType> rewinder, int width,
      int height, @NonNull Options options, List<Throwable> exceptions) throws GlideException {
    Resource<ResourceType> result = null;
    //省略部分代碼
    ........
      ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
      try {
        DataType data = rewinder.rewindAndGet();
        if (decoder.handles(data, options)) {
          data = rewinder.rewindAndGet();
          result = decoder.decode(data, width, height, options);
        }
    //省略部分代碼
    ........
    return result;
  }  
複製代碼
  • 經過以上源碼,DecodePath對象的decode方法調用了decodeResource方法,decodeResource又調用了decodeResourceWithList方法,通過前面分析,decodeResourceWithList方法中得到的decoder就是前面提到的解碼器StreamBitmapDecoder對象,因此咱們接着看StreamBitmapDecoder的decode方法
/**StreamBitmapDecoder類的decode方法**/
@Override
  public Resource<Bitmap> decode(@NonNull InputStream source, int width, int height,
      @NonNull Options options)
      throws IOException {

    // Use to fix the mark limit to avoid allocating buffers that fit entire images.
    final RecyclableBufferedInputStream bufferedStream;
    final boolean ownsBufferedStream;
    if (source instanceof RecyclableBufferedInputStream) {
      bufferedStream = (RecyclableBufferedInputStream) source;
      ownsBufferedStream = false;
    } else {
      bufferedStream = new RecyclableBufferedInputStream(source, byteArrayPool);
      ownsBufferedStream = true;
    }

    ExceptionCatchingInputStream exceptionStream =
        ExceptionCatchingInputStream.obtain(bufferedStream);
    MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream);
    UntrustedCallbacks callbacks = new UntrustedCallbacks(bufferedStream, exceptionStream);
    try {
      return downsampler.decode(invalidatingStream, width, height, options, callbacks);
    } finally {
      exceptionStream.release();
      if (ownsBufferedStream) {
        bufferedStream.release();
      }
    }
  }
複製代碼
  • 經過以上源碼,StreamBitmapDecoder的decode方法中只是對InputStream進行包裝(裝飾模式),可讓Glide進行更多操做,最終調用了downsampler.decode,這個downsampler對象則是Downsampler對象(英文註釋:Downsamples, decodes, and rotates images according to their exif orientation.),英文註釋大體意思是對圖像exif格式進行採樣、解碼和旋轉。而咱們這裏調用了它的decode方法,也就是對咱們前面包裝的流進行解碼
/**Downsampler類的decode方法**/
public Resource<Bitmap> decode(InputStream is, int requestedWidth, int requestedHeight,
      Options options, DecodeCallbacks callbacks) throws IOException {
    //省略部分代碼
    try {
      Bitmap result = decodeFromWrappedStreams(is, bitmapFactoryOptions,
          downsampleStrategy, decodeFormat, isHardwareConfigAllowed, requestedWidth,
          requestedHeight, fixBitmapToRequestedDimensions, callbacks);
      return BitmapResource.obtain(result, bitmapPool);
    } finally {
      releaseOptions(bitmapFactoryOptions);
      byteArrayPool.put(bytesForOptions);
    }
  }
/**Downsampler類的decodeFromWrappedStreams方法**/  
private Bitmap decodeFromWrappedStreams(InputStream is,
      BitmapFactory.Options options, DownsampleStrategy downsampleStrategy,
      DecodeFormat decodeFormat, boolean isHardwareConfigAllowed, int requestedWidth,
      int requestedHeight, boolean fixBitmapToRequestedDimensions,
      DecodeCallbacks callbacks) throws IOException {
    //省略部分代碼
    .........
    Bitmap downsampled = decodeStream(is, options, callbacks, bitmapPool);
    callbacks.onDecodeComplete(bitmapPool, downsampled);
    //省略部分代碼
    .........
    Bitmap rotated = null;
    if (downsampled != null) {
      //縮放效正處理
      downsampled.setDensity(displayMetrics.densityDpi);
      rotated = TransformationUtils.rotateImageExif(bitmapPool, downsampled, orientation);
      if (!downsampled.equals(rotated)) {
        bitmapPool.put(downsampled);
      }
    }
    return rotated;
  }
/**Downsampler類的decodeStream方法**/  
private static Bitmap decodeStream(InputStream is, BitmapFactory.Options options,
      DecodeCallbacks callbacks, BitmapPool bitmapPool) throws IOException {
    if (options.inJustDecodeBounds) {
      is.mark(MARK_POSITION);
    } else {
      callbacks.onObtainBounds();
    }
    int sourceWidth = options.outWidth;
    int sourceHeight = options.outHeight;
    String outMimeType = options.outMimeType;
    final Bitmap result;
    TransformationUtils.getBitmapDrawableLock().lock();
    try {
      result = BitmapFactory.decodeStream(is, null, options);
    } catch (IllegalArgumentException e) {
      //省略部分代碼
    .........
    return result;
  }  
複製代碼
  • 經過以上源碼,Downsampler對象的decode方法首先調用了decodeFromWrappedStreams方法,在decodeFromWrappedStreams方法中又調用了decodeStream方法,在該方法中調用用了BitmapFactory.decodeStream,到這裏咱們終於看到了Glide將InputStream流解析成了bitmap,而最終Downsampler對象的decode方法返回的Resource對象就是BitmapResource對象
  • 通過前面的分析,Glide已經將InputStream解碼完成,這時咱們還得再次回到DecodePath對象的decode方法,解碼完成還需轉碼,這裏再次貼一下ecodePath對象的decode方法,前面已經分析了轉碼器爲BitmapDrawableTranscoder對象,因此咱們繼續看BitmapDrawableTranscoder對象transcode作了什麼操做
/**DecodePath類的decode方法**/  
public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
      @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
    Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
    Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
    return transcoder.transcode(transformed, options);
  }
/**BitmapDrawableTranscoder類的transcode方法**/  
public Resource<BitmapDrawable> transcode(@NonNull Resource<Bitmap> toTranscode,
      @NonNull Options options) {
    return LazyBitmapDrawableResource.obtain(resources, toTranscode);
  } 
/**LazyBitmapDrawableResource類的obtain方法**/  
@Nullable
  public static Resource<BitmapDrawable> obtain(
      @NonNull Resources resources, @Nullable Resource<Bitmap> bitmapResource) {
    if (bitmapResource == null) {
      return null;
    }
    return new LazyBitmapDrawableResource(resources, bitmapResource);
  }
複製代碼
  • 經過以上源碼,BitmapDrawableTranscoder對象transcode方法最終返回了LazyBitmapDrawableResource對象,也就是將咱們解碼拿到的BitmapResource對象轉換成了LazyBitmapDrawableResource對象

到此,Glide整個圖片解碼轉碼已近完成,接着咱們再回到DecodeJob對象的decodeFromRetrievedData方法

圖片顯示
/**DecodeJob類的decodeFromRetrievedData方法**/
private void decodeFromRetrievedData() {
    Resource<R> resource = null;
    try {
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }
/**DecodeJob類的notifyEncodeAndRelease方法**/  
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
    //省略部分代碼
    .....
    Resource<R> result = resource;
    //省略部分代碼
    .....
    notifyComplete(result, dataSource);
    stage = Stage.ENCODE;
    //省略部分代碼
    .....
  }
/**DecodeJob類的notifyComplete方法**/    
 private void notifyComplete(Resource<R> resource, DataSource dataSource) {
    setNotifiedOrThrow();
    callback.onResourceReady(resource, dataSource);
  }  
複製代碼
  • 經過以上源碼,DecodeJob對象的decodeFromRetrievedData方法調用notifyEncodeAndRelease方法,將咱們上一步獲取的LazyBitmapDrawableResource傳入notifyComplete方法中,在notifyComplete調用了callback.onResourceReady,而這個callback對象就是EngineJob對象(它實現了DecodeJob.Callback接口),也許到這裏你已經忘了EngineJob對象是什麼,前面咱們開啓線程執行加載的start方法就在EngineJob對象中,因此咱們去看看EngineJob對象的onResourceReady方法
private static final Handler MAIN_THREAD_HANDLER =
      new Handler(Looper.getMainLooper(), new MainThreadCallback());
/**EngineJob類的onResourceReady方法**/
@Override
  public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    this.resource = resource;
    this.dataSource = dataSource;
    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
  }
/**EngineJob類的handleMessage方法**/
 @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;
    } 
/**EngineJob類的handleResultOnMainThread方法**/    
 @Synthetic
  void handleResultOnMainThread() {
    //省略部分代碼
    ......
    engineResource = engineResourceFactory.build(resource, isCacheable);
    hasResource = true;
   //省略部分代碼
    ......
    for (int i = 0, size = cbs.size(); i < size; i++) {
      ResourceCallback cb = cbs.get(i);
      if (!isInIgnoredCallbacks(cb)) {
        engineResource.acquire();
        cb.onResourceReady(engineResource, dataSource);
      }
    }
    //省略部分代碼
    ......
  }
/**EngineJob類的addCallback方法**/ 
private final List<ResourceCallback> cbs = new ArrayList<>(2);
void addCallback(ResourceCallback cb) {
    Util.assertMainThread();
    stateVerifier.throwIfRecycled();
    if (hasResource) {
      cb.onResourceReady(engineResource, dataSource);
    } else if (hasLoadFailed) {
      cb.onLoadFailed(exception);
    } else {
      cbs.add(cb);
    }
  }  
複製代碼
  • 經過以上源碼,前面咱們在Engine類的Load方法中已經將SingleRequest這個對象經過EngineJob對象的addCallback方法加入到了cbs這個List當中,EngineJob對象的onResourceReady方法中將咱們加載好的圖片對象經過Hanlder將數據又傳遞到了主線程(主線程更新UI),也就是handleResultOnMainThread方法中根據咱們剛剛的分析經過cb.onResourceReady將數據回調通知,cb對象就是SingleRequest對象,咱們接着看SingleRequest對象的onResourceReady回調方法
/**SingleRequest類的onResourceReady回調方法**/
@SuppressWarnings("unchecked")
@Override
public void onResourceReady(Resource<?> resource, DataSource dataSource) {
    //省略部分代碼
    .......
    Object received = resource.get();
    //省略部分代碼
    .......
    onResourceReady((Resource<R>) resource, (R) received, dataSource);
  }
/**SingleRequest類的onResourceReady方法**/  
private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
    //省略部分代碼
    .......
    status = Status.COMPLETE;
    this.resource = resource;
    //省略部分代碼
    .......
      if (!anyListenerHandledUpdatingTarget) {
        Transition<? super R> animation =
            animationFactory.build(dataSource, isFirstResource);
        target.onResourceReady(result, animation);
      }
    } 
    //省略部分代碼
    .......
  }
複製代碼

經過以上源碼,這時候咱們已經能夠看到長征勝利的曙光了,SingleRequest對象的onResourceReady回調方法中調用了resource.get(),而這個resource就是前面咱們通過解碼、轉碼獲取的LazyBitmapDrawableResource對象,而後又調用了SingleRequest對象的onResourceReady私有方法,在該方法中又調用了target.onResourceReady方法,在咱們最開始進入into方法的時候咱們已經分析過建立的target對象就是DrawableImageViewTarget對象,它繼承了抽象類ImageViewTarget,因此咱們看看抽象類ImageViewTarget的onResourceReady方法

/** LazyBitmapDrawableResource類的get()方法**/
@NonNull
  @Override
  public BitmapDrawable get() {
    return new BitmapDrawable(resources, bitmapResource.get());
  }

/** ImageViewTarget類的onResourceReady方法**/
 @Override
  public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
    if (transition == null || !transition.transition(resource, this)) {
      setResourceInternal(resource);
    } else {
      maybeUpdateAnimatable(resource);
    }
  }
/** ImageViewTarget類的setResourceInternal方法**/  
 private void setResourceInternal(@Nullable Z resource) {
    // Order matters here. Set the resource first to make sure that the Drawable has a valid and
    // non-null Callback before starting it.
    setResource(resource);
    maybeUpdateAnimatable(resource);
  }
  protected abstract void setResource(@Nullable Z resource);
複製代碼
  • 經過以上源碼,LazyBitmapDrawableResource對象的get()方法獲取了BitmapDrawable(實際就是Drawable對象),ImageViewTarget對象的onResourceReady方法經過前面分析被調用,而後該方法再調用了ImageViewTarget對象setResourceInternal方法,setResourceInternal方法最終setResource方法,setResource在ImageViewTarget對象是抽象方法,它在DrawableImageViewTarget對象中實現,最後咱們看看DrawableImageViewTarget對象setResource方法
@Override
  protected void setResource(@Nullable Drawable resource) {
    view.setImageDrawable(resource);
  }
複製代碼

到此,咱們的萬里長征終於結束了,Glide的簡單加載圖片流程已經分析完了。

最後說點

  • 最後我仍是想要把那句簡單的代碼給貼出來
Glide.with(Context).load(IMAGE_URL).into(mImageView);
複製代碼
  • 就是這樣一句簡單的代碼,它背後所走的邏輯卻讓人頭皮發麻,此時我只想說一句話「read the fuck source code」。前面咱們只是分析了Glide簡單的加載圖片流程,它的緩存使用,回調等功能原理還沒分析到,這隻能等到下篇文章了。文章中若是有錯誤,請你們給我提出來,你們一塊兒學習進步,若是以爲個人文章給予你幫助,也請給我一個喜歡和關注,同時也歡迎訪問個人我的博客

  • 對本文感興趣的朋友請繼續閱讀從源碼角度深刻理解Glide(下)

  • 參考連接

相關文章
相關標籤/搜索