Glide 4.9源碼解析-圖片加載流程

本文Glide源碼基於4.9,版本下載地址以下:Glide 4.9java

前言

因爲Glide源碼真的很複雜,所以本文只分析和貼出與圖片加載流程相關的功能以及代碼。另外本文Glide源碼基於4.9,與3.x的源碼仍是存在差別的,可是總體流程變化不大。git

對於Glide這個強大的Android圖片加載開源框架,相信你們並不陌生吧,反正筆者的話,正常項目中用的圖片加載框架大多數都是它,由於用起來真的很方便快捷,用起來便捷,但真的說明它的源碼就是那麼簡單嗎?因此今天想揭開Glide的神祕面紗,從源碼來分析一下Glide的圖片加載流程。github

在多數狀況下,咱們想要在界面加載並展現一張圖片只須要一行代碼就能實現了,以下所示:緩存

Glide.with(this).load(url).into(imageView);
複製代碼

因此咱們對Glide圖片加載流程的源碼分析能夠分爲三部曲:網絡

  • with
  • load
  • into

接下來就讓咱們一塊兒來彈奏這三部曲!多線程

1、with

1. 做用

  1. 獲得RequestManager對象
  2. 預先建立好對圖片進行一系列操做(加載,編解碼,轉碼)的對象,並添加到Glide的註冊表registry中
  3. 將Glide加載圖片的生命週期與Appliction/Activity/Fragment進行綁定

2. 流程

2.1 時序圖

首先,從使用中咱們知道,第一部曲中咱們先調用的是Glide的with方法,因此先來看看這個方法app

Glide#with框架

/** * Application類型 */
  public static RequestManager with(@NonNull Context context) {
  	//getRetriever會返回RequestManagerRetriever的單例對象
  	//RequestManagerRetriever的get會返回RequestManager對象並綁定圖片加載的生命週期
    return getRetriever(context).get(context);
  }

  /** * 非Application類型 */
  public static RequestManager with(@NonNull Activity activity) {
  	//跟Application類型同樣會調用RequestManagerRetriever的get獲取RequestManager對象
  	//不過需注意在這裏傳遞的參數爲Activity
    return getRetriever(activity).get(activity);
  }

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

能夠發現,with方法是Glide類中的一組靜態方法,在Glide中有不少的重載方法,能夠傳入Context,Activity,Fragment等,而後with裏面的實現很簡單,就一句代碼,看返回類型就知道其功能是幹嗎,就是返回一個RequestManager對象。那麼具體是如何來獲得這個對象呢,讓咱們來看看!異步

2.2 獲取RequestManagerRetriever對象

在返回RequestManager對象對象前首先會返回RequestManagerRetriever對象,無論with的參數是什麼,調用的都是getRetriever方法,並且getRetriever並無重載方法,因此獲取RequestManagerRetriever對象的步驟是同樣的,讓咱們來追蹤一下究竟是如何獲取到這個RequestManagerRetriever對象的。ide

private static RequestManagerRetriever getRetriever(@Nullable Context context) {
     ...
	//1.調用Glide.get獲取到Glide的對象,Glide對象中封裝了RequestManagerRetriever對象
	//2.經過Glide的getRequestManagerRetriever()獲取到RequestManagerRetriever對象
    return Glide.get(context).getRequestManagerRetriever();
  }
 
  public static Glide get(@NonNull Context context) {
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
          //重點關注 
          checkAndInitializeGlide(context);
        }
      }
    }
    return glide;
  }


  private static void checkAndInitializeGlide(@NonNull Context context) {
    if (isInitializing) {
	  //若是同時進行兩次初始化會拋出該異常 
      throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
          + " use the provided Glide instance instead");
    }
    isInitializing = true;
	//進行初始化操做
    initializeGlide(context);
    isInitializing = false;
  }
  private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
      ....
      	//構造Glide的實體對象,此時的builder爲GlideBuilder
        Glide glide = builder.build(applicationContext);   
      ....
  }
複製代碼

首先getRetriever方法看起來好像跟with裏面的代碼很相似,其實主要作了兩件事:

  • 經過Glide.get獲取到Glide的對象
  • 調用Glide的getRequestManagerRetriever()獲取到RequestManagerRetriever對象

在Glide的get方法就是簡單標準的單例實現。在initializeGlide中會經過GlideBuilder的build來構造Glide的實體對象,這個Glide的構造很重要,所以咱們來看看GlideBuilder的build方法是如何來構建Glide對象的

@NonNull
  Glide build(@NonNull Context context) {
    ......  
	//構建管理線程池與緩存的執行引擎
    if (engine == null) {
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(),
              GlideExecutor.newAnimationExecutor(),
              isActiveResourceRetentionAllowed);
    }

	//構建了一個RequestManagerRetriever對象
    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);

	//構建Glide對象,並將上面的衆多線程池和RequestManagerRetriever對象封裝進去
    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock(),
        defaultTransitionOptions,
        defaultRequestListeners,
        isLoggingRequestOriginsEnabled);
  }
}

public class Glide implements ComponentCallbacks2 {
      Glide(
      @NonNull Context context,
      @NonNull Engine engine,
      @NonNull MemoryCache memoryCache,
      @NonNull BitmapPool bitmapPool,
      @NonNull ArrayPool arrayPool,
      @NonNull RequestManagerRetriever requestManagerRetriever,
      @NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
      int logLevel,
      @NonNull RequestOptions defaultRequestOptions,
      @NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
      @NonNull List<RequestListener<Object>> defaultRequestListeners,
      boolean isLoggingRequestOriginsEnabled) {
          ...
          //將RequestManagerRetriever對象賦值到成員變量中
          this.requestManagerRetriever = requestManagerRetriever;
          ....
          //解碼器
          StreamBitmapDecoder streamBitmapDecoder = new StreamBitmapDecoder(downsampler, arrayPool);    
          //添加到註冊表中 
          registry
              .append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder)
              ....
              /* Models */
              //重點關注InputStreamRewinder
              .register(new InputStreamRewinder.Factory(arrayPool))
              ....
              //重點關注StringLoader.StreamFactory()
              .append(String.class, InputStream.class, new StringLoader.StreamFactory())
              .... 
              //重點關注HttpUriLoader.Factory()
        	 .append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
              ....
              //重點關注HttpGlideUrlLoader
              .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
              ....
              /* Transcoders */
	    	 //重點關注BitmapDrawableTranscoder
        	 .register(
            	 Bitmap.class,
            	 BitmapDrawable.class,
            	 new BitmapDrawableTranscoder(resources))
              .....
          
      }
}

複製代碼

從上面能夠看出Glide對象的建立乾的事情賊多,也極其複雜,總的來講其職責以下:

  • 建立RequestManagerRetriever對象
  • 建立管理線程池與緩存的執行引擎Engine對象(下文需用到)
  • 構建registry,註冊了衆多編解碼器(下文需用到)

其中在註冊表registry中,上面的代碼只列舉了幾個下面會用到的編解碼器,實際上註冊表的東西遠不止這幾個。咱們從新確認下咱們的目標獲取RequestManagerRetriever對象,在上面的代碼中已經new出了一個RequestManagerRetriever對象,並賦值到了Glide的成員變量,接下來就能夠經過Glide的getRequestManagerRetriever方法獲取到這個RequestManagerRetriever對象了。

2.3 獲取RequestManager對象

讓咱們從新看看其中一個with方法

RequestManagerRetriever#with

public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }
複製代碼

當咱們獲取到了RequestManagerRetriever對象後,就須要經過RequestManagerRetriever的get方法獲取RequestManager對象,在RequestManagerRetriever類中get跟Glide的with同樣也有不少重載方法,重載方法對不一樣參數的處理是不一樣的,根據不一樣的處理能夠分爲兩種類型的參數:

  • Application類型
  • 非Application類型(Activity/Fragment)

2.3.1 獲取到Application類型的RequestManager對象

RequestManagerRetriever#get

//Application類型
  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)) {
      //若在主線程且context不爲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());
      }
    }
	//若不在主線程或者爲Application類型的調用getApplicationManager獲取一個RequestManager對象
    return getApplicationManager(context);
  }
複製代碼

能夠發現,參數爲context的get有兩種處理:

  1. 若是在主線程且context不爲Application類型的就直接調用非Application類型的get方法
  2. 若是不在主線程或者爲Application類型的就調用getApplicationManager獲取RequestManager對象

在這裏咱們分析的是Application類型的,因此直接看getApplicationManager方法

RequestManagerRetriever#getApplicationManager

private RequestManager getApplicationManager(@NonNull Context context) {
    if (applicationManager == null) {
      synchronized (this) {
        if (applicationManager == null) {
          //get方法爲獲取Glide的單例對象,
          //因爲上面已經建立好Glide的單例對象了,因此在這裏就直接取Glide的單例對象不需建立
          Glide glide = Glide.get(context.getApplicationContext());
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(),
                  new EmptyRequestManagerTreeNode(),
                  context.getApplicationContext());
        }
      }
    }
    return applicationManager;
  }

  public interface RequestManagerFactory {
    @NonNull
    RequestManager build( @NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context);
  }

  private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() {
    @NonNull
    @Override
    public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) {
      return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
    }
  };
}
複製代碼

在上面的方法中,也是標準的單例實現,經過上面的分析咱們知道Glide已經建立好了,而且Glide的get也是單例實現,因此直接獲取到Glide對象,並new了一個ApplicationLifecycle,而後傳入Glide和ApplicationLifecycle對象等並建立了RequestManager對象從而實現與Application生命週期的綁定。

那麼爲何Glide能夠直接綁定Application的生命週期呢?

這是由於Application對象的生命週期就是App的生命週期,因此Glide加載圖片的生命週期直接與與應用程序的生命週期綁定的就行,不須要作特殊處理。

2.3.2 獲取到非Application類型的RequestManager對象

這裏咱們只以參數爲Activity類型的爲表明,由於其它非Application類型的處理與Activity基本是相似的。

RequestManagerRetriever#get

/** * 非Application類型 */
  public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
	  //若是在子線程則直接調用Aplication類型的get
      return get(activity.getApplicationContext());
    } else {
	  //判斷Activity是否銷燬
      assertNotDestroyed(activity);
	  //獲取FragmentManager對象
      FragmentManager fm = activity.getSupportFragmentManager();
	  //經過調用supportFragmentGet返回RequestManager
      return supportFragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }
複製代碼

對於非Application類型的,首先要判斷這個請求是在主線程中仍是子線程中,若是是子線程中就調用Application類型的get方法,這也能夠明白,由於在子線程中Glide的生命週期應該與Application的生命週期相一致。

若是是在主線程中,就調用supportFragmentGet方法來跟Activity的生命週期綁定。

RequestManagerRetriever#supportFragmentGet

private RequestManager supportFragmentGet( @NonNull Context context, @NonNull FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
    //獲取SupportRequestManagerFragment
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    //實現建立,添加Fragment 
    RequestManager requestManager = current.getRequestManager();
	//若是首次加載則初始化requestManager
    if (requestManager == null) { 
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
	  //設置到SupportRequestManagerFragment中
	  current.setRequestManager(requestManager);
    }
    return requestManager;
  }
複製代碼

supportFragmentGet是如何與Activity進行綁定的呢?其流程以下:

  1. 建立隱藏的Fragment
  2. 向當前的Activity添加一個隱藏的Fragment
  3. 建立RequestManager對象,而後將RequestManager與隱藏的Fragment的生命週期進行綁定

也許你會問爲何綁定了Activity中隱藏的Fragment生命週期就能與Activity進行綁定了呢?這是由於Fragment的生命週期與Activity是同步的,因此經過綁定的隱藏的Fragment就能監聽Activity的生命週期,進而實現Glide加載圖片的生命週期與Activity同步,而且經過這樣的方法還能避免Glide持有Activity的實例而發生內存泄漏問題。

3. 小結

到這裏with的工做就結束了,讓咱們來總結一下with的主要工做

  • 構建Glide對象
    • 建立管理線程池與緩存的執行引擎Engine對象
    • 構建registry,註冊了衆多編解碼器
    • 構建RequestManagerRetriever對象
  • 構建RequestManager對象
    • 若是在子線程中加載圖片或with中的參數爲Application類型,則Glide圖片加載的生命週期與Application生命週期綁定
    • 不然,Glide圖片加載的生命週期與Activity或Fragment的生命週期綁定,綁定的方式:向當前的Activity/Fragment添加一個隱藏的Fragment,而後綁定這個隱藏的Fragment的生命週期。

2、load

1. 做用

建立一個目標爲Drawable的圖片加載請求,傳入須要加載的資源(String,URL,URI等)

2. 流程

2.1 時序圖

2.2 建立RequestBuilder對象

從上面對with的分析,咱們知道with最終會返回一個RequestManager對象,故第二部曲的開始就是RequestManager的load方法。

RequestManager#load

public RequestBuilder<Drawable> load(@Nullable String string) {
  	//1.asDrawable建立一個目標爲Drawable的圖片加載請求
  	//2.調用load將加載的資源傳入
    return asDrawable().load(string);
  }

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

  public RequestBuilder<Drawable> load(@Nullable URL url) {
    return asDrawable().load(url);
  }
.....
複製代碼

能夠發現load在RequestManager也是有不少重載方法的,可是下面咱們只分析最多見的加載圖片的load參數,即load(String url)。

在RequestManager的load方法中,首先會先調用asDrawable,讓咱們來看看asDrawable

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

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

上面的代碼很簡單,就是建立了一個目標爲Drawable的圖片加載請求RequestBuilder。

2.3 傳入圖片URL地址

因爲asDrawable返回的是RequestBuilder對象,所以下一步將會調用RequesBuilder的load方法

RequesBuilder#load

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

  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
  	//將數據賦值給RequestBuilder的靜態成員變量
    this.model = model;
    isModelSet = true;
    return this;
  }
複製代碼

上面的代碼很容易理解,load調用了loadGeneric方法,loadGeneric方法中將數據,此時將String類型的model賦值給了RequestBuilder的靜態成員變量。

3. 小結

load估計是三部曲中最簡單的一部曲子了,代碼簡單,也很容易理解。此部曲也是3.x與4.9的區別之一,在3.x的源碼中load原本還應該完成一項任務,即預先建立好對圖片進行一系列操做(加載,編解碼,轉碼)的對象。而經過上述對with的分析,咱們知道在4.9的源碼中,這項工做已經交給with來處理了,因此load相比較其它兩個來講,其工做是比較簡單的。

3、into

!!!高能預警,into的源碼分析將會很長很長很長

1. 做用

在子線程中網絡請求解析圖片,並回到主線程中展現圖片

2. 流程

下列的源碼基於load參數爲String,不採起內存緩存,磁盤緩存的狀況下

在上面對load的解析中咱們知道,load執行完後返回的是RequestBuilder對象,因此into的入口就是RequestBuilder

RequestBuilder#into

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    
     .....
	//返回ViewTarget對象
    return into(
    	//glideContext爲GlideContext類型
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions,
        //含有綁定主線程Handler的線程池
        Executors.mainThreadExecutor());
}
複製代碼

在上面的代碼中,咱們知道在調用into以前會先獲取要傳遞的參數,這裏咱們重點關注第一個參數和第四個參數。

2.1 建立ViewTarget對象

首先咱們先分析GlideContext的buildImageViewTarget方法.

GlideContext#buildImageViewTarget

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

此時傳入的transcodeClass其實就是咱們在第二部曲中分析的asDrawable中傳入的Drawable.class,而後繼續調用了ImageViewTargetFactory的buildTarget方法。

ImageViewTargetFactory#buildTarget

public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view, @NonNull Class<Z> clazz) {
    if (Bitmap.class.equals(clazz)) {
	  //如果調用了asBitmap方法
      return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
      //不然
      return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
    } else {
      throw new IllegalArgumentException(
          "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
  }
複製代碼

由於咱們並無調用asBitmap方法,而且傳入的是Drawable類型,因此返回的ViewTarget對象應該是DrawableImageViewTarget,這個對象在展現圖片時將會用到。

!!!注:下文代碼中出現的target,若是沒有特殊說明都是DrawableImageViewTarget對象。

2.2 建立MAIN_THREAD_EXECUTOR

讓咱們回到前面的into方法。

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    ....
	//返回ViewTarget對象
    return into(
    	//buildImageViewTarget建立ViewTarget對象
    	//transcodeClass若調用了asBitmap則爲Bitmap,相應的返回BitmapImageViewTarget,
	    //不然transcodeClass爲Drawable類型,返回DrawableImageViewTarget 
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions,
        //含有綁定主線程Handler的線程池
        Executors.mainThreadExecutor());
  }
複製代碼

接着咱們繼續分析第四個參數

Executors#mainThreadExecutor

private static final Executor MAIN_THREAD_EXECUTOR =
      new Executor() {
       //綁定主線程的Looper
        private final Handler handler = new Handler(Looper.getMainLooper());

        @Override
        public void execute(@NonNull Runnable command) {
          handler.post(command);
        }
      };

public static Executor mainThreadExecutor() {
    return MAIN_THREAD_EXECUTOR;
  }
複製代碼

從上面能夠發如今這個mainThreadExecutor中返回的是MAIN_THREAD_EXECUTOR,而MAIN_THREAD_EXECUTOR聲明瞭一個綁定了主線程Looper的Handler,而後這個線程池的execute方法會執行handler的post方法,至關於在主線程中執行command的run方法。(這裏先講明白這個線程池,由於當分析到最後在主線程中顯示圖片時會從新分析到這個參數,另外這裏涉及到了Handler機制的知識,不懂的能夠看看前面寫的博客Android之Handler機制

分析完了into的兩個參數,咱們接下來就看看這個重載into方法

RequestBuilder#into

private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options, Executor callbackExecutor) {
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }
    //構建Requset對象,發出加載圖片請求
    //注意第四個參數傳進去的是含有綁定主線程的Handler的線程池
    Request request = buildRequest(target, targetListener, options, callbackExecutor);
    //在開始前先釋放掉target對象已存在的請求
    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      request.recycle();
      
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        previous.begin();
      }
      return target;
    }
		
    requestManager.clear(target);

	//將請求設置到target中
    target.setRequest(request);
	//分發並執行網絡請求Request,此時的requestManager就是
    requestManager.track(target, request);

    return target;
  }
複製代碼

咱們能夠發如今這個方法中,其實主要的工做有兩個:一是構建網絡請求的Request,二是執行網絡請求對象Request,接下來咱們就分別對這兩個工做進行分析。

2.3 構建網絡請求對象Request

RequestBuilder#buildRequest

private Request buildRequest( Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> requestOptions, Executor callbackExecutor) {
    //重點關注buildRequestRecursive方法 
    return buildRequestRecursive(
        target,
        targetListener,
        /*parentCoordinator=*/ null,
        transitionOptions,
        requestOptions.getPriority(),
        requestOptions.getOverrideWidth(),
        requestOptions.getOverrideHeight(),
        requestOptions,
        callbackExecutor);
  }

  private Request buildRequestRecursive( Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, @Nullable RequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight, BaseRequestOptions<?> requestOptions, Executor callbackExecutor) {

    .....
    //重點關注buildThumbnailRequestRecursive方法
    Request mainRequest =
        buildThumbnailRequestRecursive(
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions,
            callbackExecutor);

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


  private Request buildThumbnailRequestRecursive( Target<TranscodeType> target, RequestListener<TranscodeType> targetListener, @Nullable RequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight, BaseRequestOptions<?> requestOptions, Executor callbackExecutor) {
      ....
      //重點關注,關鍵代碼
	  Request fullRequest =
          obtainRequest(
              target,
              targetListener,
              requestOptions,
              coordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overrideHeight,
              callbackExecutor);
      ........ 
  }

  private Request obtainRequest( Target<TranscodeType> target, RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> requestOptions, RequestCoordinator requestCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight, Executor callbackExecutor) {
    //調用了SingleRequest的obtain方法,將load中調用的全部API參數都組裝到Request對象當中
    //此時的callbackExecutor爲含有綁定主線程Handler的線程池 
    return SingleRequest.obtain(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory(),
        callbackExecutor);
  }
複製代碼

通過一步一步調用,最終將會執行SingleRequest的obtain方法,因此咱們繼續看這個方法

SingleRequest#obtain方法

public static <R> SingleRequest<R> obtain( Context context, GlideContext glideContext, Object model, Class<R> transcodeClass, BaseRequestOptions<?> 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, Executor callbackExecutor) {
    @SuppressWarnings("unchecked") SingleRequest<R> request =
        (SingleRequest<R>) POOL.acquire();
    if (request == null) {
	  //建立SingleRequest對象
      request = new SingleRequest<>();
    }
	//將傳入load中的API參數賦值到SingleRequest的成員變量
	//最後一個參數爲主線程的線程池
    request.init(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        engine,
        animationFactory,
        callbackExecutor);
    return request;
  }
  //對成員變量賦值
  private synchronized void init( Context context, GlideContext glideContext, Object model, Class<R> transcodeClass, BaseRequestOptions<?> 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, Executor callbackExecutor) {
    this.context = context;
    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.targetListener = targetListener;
    this.requestListeners = requestListeners;
    this.requestCoordinator = requestCoordinator;
    this.engine = engine;
    this.animationFactory = animationFactory;
    this.callbackExecutor = callbackExecutor;
    status = Status.PENDING;

    if (requestOrigin == null && glideContext.isLoggingRequestOriginsEnabled()) {
      requestOrigin = new RuntimeException("Glide request origin trace");
    }
  }
複製代碼

這個obtain方法其實就是建立了SingleRequest對象,而後調用了init方法進行成員變量的賦值,因此構建的網絡請求對象就是SingleRequest對象。

2.4 執行網絡請求對象Request

讓咱們回到into方法

private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options, Executor callbackExecutor) {
    //構建Requset對象,發出加載圖片請求
    //最終構建的是SingleRequest對象
    Request request = buildRequest(target, targetListener, options, callbackExecutor);  
    .....
	//分發並執行網絡請求Request,此時的requestManager就是RequestManager對象
    //target爲上述建立的DrawableImageViewTarget(若是忘記能夠從新看回2.1)
    //request就是建立完成的singleRequest對象 
    requestManager.track(target, request);

    return target;
  }
複製代碼

這時候咱們已經成功構建出了SingleRequest對象了,而後調用了RequestManager的track方法進行分發並執行這個請求

2.4.1 加載前

RequestManager#track

synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);
	//執行網絡請求
    requestTracker.runRequest(request);
  }
複製代碼

RequestTracker#runRequest

public void runRequest(@NonNull Request request) {
    //將每一個提交的請求加入到一個set中,從而實現管理請求
    requests.add(request);
	//判斷Glide當前是否處於暫停狀態
    if (!isPaused) {
	  //若是不暫停,則調用SingleRequest的begin方法來執行request
      request.begin();
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
	  //若是暫停,則先將當前的請求添加到待執行隊列裏面,等待暫停狀態解除後再執行
      pendingRequests.add(request);
    }
  }
複製代碼

在加載圖片前,即開啓網絡請求前咱們須要將每一個請求加到set中來進行管理請求,而且還須要判斷Glide當前的狀態,由於咱們如今分析的是圖片加載流程,顯然這裏的Glide不是暫停狀態,因此會執行request的begin方法,因爲在上面咱們已經分析了網絡請求對象爲SingleRequest,因此這裏的request爲SingleRequest對象。

2.4.2 加載時

接着咱們來看看SingleRequest的begin方法

SingleRequest#begin

public synchronized void begin() {
    ....
	//model爲load傳入的圖片URL地址
    if (model == null) {
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        width = overrideWidth;
        height = overrideHeight;
      }
       
      int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
	  //若是傳入的URL地址爲空,則會調用onLoadFailed
      onLoadFailed(new GlideException("Received null model"), logLevel);
      return;
    }

    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
	  //重點關注
      onSizeReady(overrideWidth, overrideHeight);
    } else {
    &emsp;//getsize計算寬高,而後執行onSizeReady方法
      target.getSize(this);
    }

    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
      //在圖片請求成功前,會先使用Loading佔位圖代替最終的圖片顯示 
      target.onLoadStarted(getPlaceholderDrawable());
    }
    .....
  }
複製代碼
1. onLoadFailed

從上面的代碼中咱們能夠發現當model爲null時,即load傳入的圖片地址爲空時,會調用onLoadFailed方法

SingleRequest#onLoadFailed

private synchronized void onLoadFailed(GlideException e, int maxLogLevel) {
    .....

    loadStatus = null;
    status = Status.FAILED;

    isCallingCallbacks = true;
    try {
      //TODO: what if this is a thumbnail request?
      boolean anyListenerHandledUpdatingTarget = false;
      if (requestListeners != null) {
        for (RequestListener<R> listener : requestListeners) {
          anyListenerHandledUpdatingTarget |=
              listener.onLoadFailed(e, model, target, isFirstReadyResource());
        }
      }
      anyListenerHandledUpdatingTarget |=
          targetListener != null
              && targetListener.onLoadFailed(e, model, target, isFirstReadyResource());

      if (!anyListenerHandledUpdatingTarget) {
	  	//重點關注這個方法
        setErrorPlaceholder();
      }
    } finally {
      isCallingCallbacks = false;
    }

    notifyLoadFailed();
  }


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

    Drawable error = null;
	//先獲取fallback的圖片
    if (model == null) {
      error = getFallbackDrawable();
    }
    //若沒有設置fallback圖,則獲取error圖
    if (error == null) {
      error = getErrorDrawable();
    }
    //若沒有error圖,則再獲取一個loading的佔位圖
    if (error == null) {
      error = getPlaceholderDrawable();
    }
    //target爲DrawableImageViewTarget 
    target.onLoadFailed(error);
  }
複製代碼

在onLoadFailed方法中咱們只須要關注setErrorPlaceholder方法,而在setErrorPlaceholder中主要的邏輯就是獲取錯誤時須要展現的圖片,按fallback>error>loading的優先級來獲取錯誤時的圖片,而後調用DrawableImageViewTarget的onLoadFailed方法。經過查看DrawableImageViewTarget,咱們能夠發現這個類中並無onLoadFailed方法,因此咱們天然而然找父類ImageViewTarget是否存在這個方法.

ImageViewTarget#onloadFailed

public void onLoadFailed(@Nullable Drawable errorDrawable) {
    super.onLoadFailed(errorDrawable);
    setResourceInternal(null);
	//調用setDrawable將圖片顯示出來
    setDrawable(errorDrawable);
  }

  public void setDrawable(Drawable drawable) {
    //view就是ImageView,將圖片展現出來
    view.setImageDrawable(drawable);
  }

複製代碼

到這裏,錯誤的圖片就被顯示出來,從這裏咱們能夠看出Glide顯示錯誤的圖片的原則就是:當傳入圖片的url爲null時,會才採用fallback/error/loading的佔位圖進行代替。

2. onLoadStarted

分析完onLoadFailed,咱們回到SingleRequest的begin方法,原本按代碼順序接下來應該分析的是onSizeReady,可是因爲這個方法比較複雜而且onLoadStarted與onLoadStarted很相似,因此咱們先分析onLoadStarted,把onSizeReady放到最後。

SingleRequest#begin 與onLoadStarted相關的代碼

if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
      //在圖片請求成功前,會先使用Loading佔位圖代替最終的圖片顯示 
      target.onLoadStarted(getPlaceholderDrawable());
    }
複製代碼

看上面這個邏輯就是當圖片正在請求時或者等待執行onSizeReady方法時,就執行DrawableImageViewTarget的onLoadStarted方法,從onLoadFailed方法的分析咱們已經知道,onLoadFailed方法是在DrawableImageViewTarget父類ImageViewTarget中,故onLoadStarted也是在ImageViewTarget中,至於參數就是loading的佔位圖。

ImageViewTarget#onLoadStarted

public void onLoadStarted(@Nullable Drawable placeholder) {
    super.onLoadStarted(placeholder);
    setResourceInternal(null);
	//在圖片請求開始前,會先使用Loading佔位圖代替最終的圖片顯示
    setDrawable(placeholder);
  }

  public void setDrawable(Drawable drawable) {
    //將圖片展現出來
    view.setImageDrawable(drawable);
  }
複製代碼

而後將loading的佔位圖顯示出來,即圖片請求成功前,會使用Loading佔位圖代替最終的圖片顯示。這也算是咱們常用的一個功能了。

3. onSizeReady

到這裏咱們終於要分析重頭戲onSizeReady了,咱們先貼出相關代碼

SingleRequest#begin 與onSizeReady相關的代碼

//圖片加載有兩種狀況:
	//1.使用了override()的API爲圖片指定了固定寬高
	//2.無使用
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
		//第一種狀況,指定了寬高的話調用onSizeReady加載
      onSizeReady(overrideWidth, overrideHeight);
    } else {
    &emsp;//getsize計算寬高,而後執行onSizeReady方法
      //(從DrawableImageViewTarget中向上追蹤,會在ViewTarget中發現這個方法)
      target.getSize(this);
    }
複製代碼

這個咱們只分析onSizeReady,由於getSize方法最終也是會調用onSizeReady的。

SingleRequest#onSizeReady

@Override
  public synchronized void onSizeReady(int width, int height) {
    ....
    status = Status.RUNNING;

    loadStatus =
    	//重點關注,調用Engine的load構建任務
    	//重點關注倒數第二個參數,傳入自身SingleRequest,在回調的時候會使用
    	//重點關注倒數第一個參數,傳入有綁定主線程的Handler的線程池callbackExectuter
        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,
            callbackExecutor);
  }
複製代碼

能夠看出onSizeReady的實現交給了Engine的load方法實現了,這個Engine對象就是在第一部曲with中Glide構建時提到的執行引擎,在這裏還須要特別注意的是傳給load的最後兩個參數,由於這兩個參數在後面的分析須要用到。

構建任務

Engine#load

public synchronized <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, Executor callbackExecutor) {
    
    .....
	//從緩存中查找key對應的任務
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
	  //若是走到這說明該任務已經正在執行了,無需再次構建執行
	  //能夠先不看,從後面分析完後從新回頭看這個
      current.addCallback(cb, callbackExecutor);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }
	//走到這,說明這是個新任務
    //建立EngineJob對象,用來開啓線程(異步加載圖片)
    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);
    //建立DecodeJob對象,用來對圖片解碼
    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, callbackExecutor);
	//執行任務
    engineJob.start(decodeJob);
    ...  
    return new LoadStatus(cb, engineJob);
  }
複製代碼

結合上面的代碼和註釋,咱們能夠知道Engine.load的主要工做:

  • 建立EngineJob對象,用來開啓線程
  • 建立DeodeJob對象,用來對照片進行解碼
  • 添加回調的對象和線程池
  • 執行任務
執行任務

EngineJob#start

public synchronized void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
	//獲取線程池
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
	//執行DecodeJob的run方法
    executor.execute(decodeJob);
  }
複製代碼

調用線程池的execute方法,故接下來會執行DecodeJob的run方法

DecodeJob#run

public void run() {
    ....
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
	  //重點關注,調用runWrapped
      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 Stage getNextStage(Stage current) {
    switch (current) {
      case INITIALIZE:
	  	//若配置的緩存策略容許從資源緩存中讀取數據,則返回Stage.RESOURCE_CACHE
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
      case RESOURCE_CACHE:
	  	//若配置的緩存策略容許從源數據緩存讀取數據,則返回Stage.DATA_CACHE
        return diskCacheStrategy.decodeCachedData()
            ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
      case DATA_CACHE:
        //若只能容許從緩存中讀取數據,則直接FINISH,不然返回Stage.SOURCE,表示加載新的資源
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
  }

  //獲取這個場景的執行者
  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;
	// 調用 DataFetcherGenerator.startNext() 執行了請求操做
	//咱們這裏主要分析的是無緩存狀況,因此這裏的DataFetcherGenerator應該是SourceGenerator
    while (!isCancelled && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

      if (stage == Stage.SOURCE) {
        reschedule();
        return;
      }
    }
    .....
  }
複製代碼

怎麼執行任務呢?大致上能夠分爲三個步驟:

  1. 獲取任務場景
  2. 獲取任務場景的執行者
  3. 執行者執行任務

場景和執行者是一一對應的,因爲咱們如今分析的是第一次加載圖片,而且沒有配置緩存策略,因此對應的任務場景爲無緩存狀況,與之相對應的執行者就是SourceGenerator對象,因此當執行任務時調用的是SourceGenerator的startNext方法

SourceGenerator#startNext

public boolean startNext() {
    ......
    boolean started = false;
    while (!started && hasNextModelLoader()) {
	  //從DecodeHelper的數據加載集合中, 獲取一個數據加載器 
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;

		//使用加載器fetcher執行數據加載
		//此fetcher爲HttpUrlFetcher對象
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }
複製代碼
獲取數據加載器

首先來看看如何獲得數據加載器的集合

DecodeHelper#getLoadData

List<LoadData<?>> getLoadData() {
    if (!isLoadDataSet) {
      isLoadDataSet = true;
      loadData.clear();
	  //從Glide註冊的register中獲取modelLoaders
      List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
      //遍歷modelLoaders
      for (int i = 0, size = modelLoaders.size(); i < size; i++) {
        //此時分析的model爲url的string格式,該其中一個實現類爲StringLoader 
        ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
		//經過StringLoader構造loadData
		//通過Glide的registry分析後最終會執行HttpGlideUrlLoader的buildLoadData方法
		//最終的loadData封裝了HttpUrlFetcher對象
        LoadData<?> current =
            modelLoader.buildLoadData(model, width, height, options);
        if (current != null) {
		  //添加到loadData集合中
          loadData.add(current);
        }
      }
    }
	//最終返回的是含有HttpUrlFetcher對象的loadData集合
    return loadData;
  }
複製代碼

咱們來一步步解剖這個方法,首先須要從Glide註冊的registry中獲取modelLoaders,由於咱們全文以String爲例子,因此這裏的model將是String類型的。

!!!注意:在註冊表中註冊的都是ModelLoader的實現ModelLoaderFactory靜態工廠類,當調用Registry的getModelLoaders時會調用工廠類中的build方法,這裏就不貼出這其中的過程了,如今咱們只須要知道當調用getModelLoaders方法時會調用註冊表中對應工廠類的build方法。如今咱們須要回頭看看Glide構建時的註冊表,看看model爲String類型時有那些ModelLoader的靜態工廠類,下面只列舉幾個:

Glide#Glide構造器

registry
		//重點關注StringLoader.StreamFactory()
        .append(String.class, InputStream.class, new StringLoader.StreamFactory())
        .append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
        .append(
            String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory())
複製代碼

這裏咱們以StringLoader.StreamFactory爲例子,因爲調用了getModelLoaders方法,因此會執行StringLoader.StreamFactory的build方法

StringLoader.StreamFactory()

public static class StreamFactory implements ModelLoaderFactory<String, InputStream> {

    @NonNull
    @Override
    public ModelLoader<String, InputStream> build( @NonNull MultiModelLoaderFactory multiFactory) {
      //從Glide的registry的models註冊表能夠得知
      //這時候的multiFactory爲HttpUriLoader.Factory() 
      //不斷追蹤下去得知最終參數裏返回的是HttpGlideUrlLoader對象
      return new StringLoader<>(multiFactory.build(Uri.class, InputStream.class));
    }
    .....
  }
複製代碼

從build方法中,構建了StringLoader對象,可是其中的參數又調用了另一個MultiModelLoaderFactory,這時候咱們須要看會Glide的註冊表中,而後找到參數爲Uri.class, InputStream.class時構建的MultiModelLoaderFactory對象

Glide#Glide的構造器

registry       
		//重點關注HttpUriLoader.Factory()
        .append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
複製代碼

能夠發現這時候的MultiModelLoaderFactory對象將會是HttpUriLoader.Factory()類型的,因此咱們還須要看看其中的build方法

HttpUriLoader.Factory#build

public ModelLoader<Uri, InputStream> build(MultiModelLoaderFactory multiFactory) {
      //根據Glide中的registry中的Models註冊表能夠知道
      //這時候的multiFactory爲HttpGlideUrlLoader.Factory()
      return new HttpUriLoader(multiFactory.build(GlideUrl.class, InputStream.class));
    }
複製代碼

仍是跟上面同樣的步驟,繼續查看Glide的註冊表,找出參數爲GlideUrl.class, InputStream.class的MultiModelLoaderFactory對象

registry    
		//重點關注HttpGlideUrlLoader
        .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
複製代碼

再看看HttpGlideUrlLoader.Factory的build方法

HttpGlideUrlLoader.Factory#build

public ModelLoader<GlideUrl, InputStream> build(MultiModelLoaderFactory multiFactory) {
      //最終返回的是HttpGlideUrlLoader對象
      return new HttpGlideUrlLoader(modelCache);
    }
複製代碼

這裏的build方法返回的是HttpGlideUrlLoader類型,因此最終構建StringLoader對象中的參數將是HttpGlideUrlLoader類型的。因而咱們看看StringLoader的構造器的實現。

StringLoader#StringLoader構造器

public StringLoader(ModelLoader<Uri, Data> uriLoader) {
    //此時的uriLoader爲HttpGlideUrlLoader對象,賦值給靜態成員變量
    this.uriLoader = uriLoader;
  }
複製代碼

構建器就是簡單的給成員變量賦值,此時的uriLoader爲HttpGlideUrlLoader對象。這就是getModelLoaders所作的事,咱們繼續分析DecodeHelper的getLoadData方法,當獲取到了String的modelLoaders後會遍歷每個modelLoader,而後調用modelLoader的buildLoadData來構造loadData對象,這裏咱們直接用上面分析獲得的StringLoader爲例,讓咱們看看StringLoader的buildLoadData的實現

StringLoader#buildLoadData

public LoadData<Data> buildLoadData(@NonNull String model, int width, int height, @NonNull Options options) {
    Uri uri = parseUri(model);
    if (uri == null || !uriLoader.handles(uri)) {
      return null;
    }
	//此時的uriLoader爲HttpGlideUrlLoader對象
    return uriLoader.buildLoadData(uri, width, height, options);
  }
複製代碼

由上面分析咱們已經知道此時StringLoader中的uriLoader爲HttpGlideUrlLoader對象,因此會繼續調用HttpGlideUrlLoader的buildLoadData方法

HttpGlideUrlLoader

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);
	//建立了一個LoadData對象, 而且封裝了HttpUrlFetcher對象
    return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
  }
複製代碼

其它代碼咱們並不須要過多的關注,只須要關注最後的返回值,能夠發現最後返回的是封裝了HttpUrlFetcher的LoadData對象,這樣getLoadData方法獲取到的就是封裝了HttpUrlFetcher的LoadData對象。讓咱們回到SourceGenerator的startNext方法。

SourceGenerator#startNext

public boolean startNext() {
    ......
    boolean started = false;
    while (!started && hasNextModelLoader()) {
	  //最終獲取的的對象就是封裝了HttpUrlFetcher的LoadData對象
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;

		//使用加載器fetcher執行數據加載
		//此fetcher爲HttpUrlFetcher對象
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }
複製代碼

上面已經分析了loadData是封裝了HttpUrlFetcher的LoadData對象,因此執行數據加載其實就是調用了HttpUrlFetcher的loadData方法。

執行數據加載

HttpUrlFetcher#loadData

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());
	  //將inputStream回調出去,callback爲DataCallback
      callback.onDataReady(result);
    }
      ......
  }


  //網絡請求代碼,利用了HttpURLConnection進行網絡請求
  private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException {
    ......
    //靜態工廠模式建立HttpUrlConnection對象
    urlConnection = connectionFactory.build(url);
    for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
      urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
    }
	//設置鏈接超時時間爲2500ms
    urlConnection.setConnectTimeout(timeout);
	//設置讀取超時時間爲2500ms
    urlConnection.setReadTimeout(timeout);
	//不使用http緩存
    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);
    } 
    ......  
  }

  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();
    }
	//最終返回的是圖片的InputStream對象,還未開始讀取數據
    return stream;
  }
複製代碼

能夠發現執行數據加載有兩個工做,首先是獲取數據的輸入流,這裏採起的是HttpURLConnection進行網絡請求,最終獲取到的是數據的InputStream對象,記住這時候並未開始讀取數據。

返回數據

當獲取到輸入流後,還須要將這個輸入流返回出去,怎麼返回呢?

callback.onDataReady(result);
複製代碼

能夠發現這裏使用的是回調的方法將數據的輸入流回調出去。此時callbak爲DataCallback對象,根據回調的使用咱們知道下一步應該要找到實現DataCallback接口的類,怎麼找呢?這時候就須要往回找,調用loadData方法的是在SourceGenerator的startNext方法,因此咱們首選目標就是這個SourceGenerator類

SourceGenerator#onDataReady

class SourceGenerator implements DataFetcherGenerator, DataFetcher.DataCallback<Object>, DataFetcherGenerator.FetcherReadyCallback {
        
  ........
  public void onDataReady(Object data) {
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
    if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      dataToCache = data;
      ....
    } else {
	  //繼續回調FetcherReadyCallback的onDataFetcherReady方法,將data回調出去
      cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
          loadData.fetcher.getDataSource(), originalKey);
    }
  }
}
複製代碼

機智如咱們!果真SourceGenerator類實現了DataFetcher.DataCallback這個接口,而且在這個類找到了onDataReady方法,這個方法仍是選擇回調,回調了FetcherReadyCallback的onDataFetcherReady方法,因而咱們在往回找,並在心中默唸:在哪一個類中調用了SourceGenerator的startNext方法呢?而後你就會發現是在DecodeJob的run方法中調用了startNext這個方法,而後立刻看看DecodeJob是否實現了onDataFetcherReady接口!

DecodeJob#onDataFetcherReady

class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, Runnable, Comparable<DecodeJob<?>>, Poolable {
        
        
     .......   
	public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
    .......
    if (Thread.currentThread() != currentThread) {
      runReason = RunReason.DECODE_DATA;
      callback.reschedule(this);
    } else {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
	  	//解析獲取的數據
        decodeFromRetrievedData();
      } finally {
        GlideTrace.endSection();
      }
    }
  }
  
   private void decodeFromRetrievedData() {
    ....
    try {
	  //獲取解析後
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
	  //通知外界資源獲取成功 
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }
        
        
}
複製代碼

哇!超神了!果真是這樣!onDataFetcherReady方法中主要工做有兩件:

  1. 解析獲取的數據
  2. 返回圖片資源

咱們先看看是如何解析數據的

2.5 解析數據

DecodeJob

private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data, DataSource dataSource) throws GlideException {
    try {
      ......

	  //重點關注decodeFromFetcher方法
      Resource<R> result = decodeFromFetcher(data, dataSource);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Decoded result " + result, startTime);
      }
      return result;
    } 
    ......  
  }

  private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource) throws GlideException {
    //獲取當前數據類的解析器LoadPath,此時的data爲InputStream對象 
    LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
	//經過解析器來解析數據
    return runLoadPath(data, dataSource, path);
  }

  private <Data, ResourceType> Resource<R> runLoadPath(Data data, DataSource dataSource, LoadPath<Data, ResourceType, R> path) throws GlideException {
    Options options = getOptionsWithHardwareConfig(dataSource);
	//此時的data爲InputStream對象,故rewinder爲InputStreamRewinder對象
    DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
    try {
      //將數據解析轉移到LoadPath.load方法中
      return path.load(
          rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
    } finally {
      rewinder.cleanup();
    }
  }
複製代碼

這裏的rewinder的獲取跟modelLoaders的獲取同樣須要從新看Glide構建中的註冊表registry,在這裏再也不詳細說明,由於data爲InputStream對象,因此rewinder爲InputStreamRewinder對象,而後調用LoadPath的load方法實現解析數據

LoadPath

public Resource<Transcode> load(DataRewinder<Data> rewinder, @NonNull Options options, int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException {
    List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire());
    try {
	  //重點關注
      return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
    } finally {
      listPool.release(throwables);
    }
  }

  private Resource<Transcode> loadWithExceptionList(DataRewinder<Data> rewinder, @NonNull Options options, int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback, List<Throwable> exceptions) throws GlideException {
    Resource<Transcode> result = null;
    //遍歷DecodePath集合
    for (int i = 0, size = decodePaths.size(); i < size; i++) {
      DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i);
      try {
	  	//調用DecodePath.decode真正進行數據解析
        result = path.decode(rewinder, width, height, options, decodeCallback);
      } catch (GlideException e) {
        exceptions.add(e);
      }
      if (result != null) {
        break;
      }
    }

    if (result == null) {
      throw new GlideException(failureMessage, new ArrayList<>(exceptions));
    }

    return result;
  }

複製代碼

DecodePath

public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
    //獲取到Resource<Bitmap>對象 
    Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
	//將資源轉化爲目標效果,如在構建request時設置的CenterCrop
    Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
	//將數據轉化爲目標格式,將Resource<Bitmap>轉換爲LazyBitmapDrawableResource對象
	//可經過LazyBitmapDrawableResource的get獲取到BitmapDrawable對象
	//該transcoder爲BitmapDrawableTranscoder
    return transcoder.transcode(transformed, options);
  }
複製代碼

LoadPath的load方法最終會調用DecodePath的decode來解析數據,DecodePath的decode的主要工做就是獲取到Resource對象,而後還要將Resource對象轉化成LazyBitmapDrawableResource。考慮到篇幅問題,在這裏就不分析如何獲得Resource對象,只分析如何將數據轉化爲目標格式,能夠經過Glide構造中的註冊表中找出Bitmap轉化成Drawable的轉化器爲BitmapDrawableTranscoder,因此實際上調用了BitmapDrawableTranscoder的transcode來進行轉換

BitmapDrawableTranscoder#transcode

public Resource<BitmapDrawable> transcode(@NonNull Resource<Bitmap> toTranscode, @NonNull Options options) {
    //獲取LazyBitmapDrawableResource對象 
    return LazyBitmapDrawableResource.obtain(resources, toTranscode);
  }
複製代碼

LazyBitmapDrawableResource

public static Resource<BitmapDrawable> obtain( @NonNull Resources resources, @Nullable Resource<Bitmap> bitmapResource) {
    if (bitmapResource == null) {
      return null;
    }
	//建立了一個LazyBitmapDrawableResource對象
    return new LazyBitmapDrawableResource(resources, bitmapResource);
  }
  
  public BitmapDrawable get() {
    //返回一個BitmapDrawable對象
    return new BitmapDrawable(resources, bitmapResource.get());
  }
複製代碼

追蹤下去能夠發現transcode最終會獲得一個封裝了Resource的對象,而後看LazyBitmapDrawableResource的get方法,能夠獲得一個BitmapDrawable對象,即目標格式。到這裏就成功將數據解析成LazyBitmapDrawableResource對象。

2.6 在主線程中顯示圖片

既然解析完數據,剩下的工做就是將數據顯示出來,因而咱們得從新看回DecodeJob的decodeFromRetrievedData方法

DecodeJob

private void decodeFromRetrievedData() {
    ....
    try {
	  //解析成功後resource爲封裝了Resource<Bitmap>的LazyBitmapDrawableResource對象
      //可經過get方法獲取到BitmapDrawable對象
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
	  //通知外界資源獲取成功 
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }

  private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
    .....
    //重點關注
    notifyComplete(result, dataSource);
    ......
    
  }

  private void notifyComplete(Resource<R> resource, DataSource dataSource) {
    setNotifiedOrThrow();
	//回調,注意此時的callback爲EngineJob(可回頭看Engine中DecodeJob的建立)
    callback.onResourceReady(resource, dataSource);
  }
複製代碼

2.6.1 回調數據

嘻嘻,看到最後又來到了咱們熟悉的回調方法,看到這個callback你可能會一臉茫然,這個callback哪一個對象呢?別急,讓咱們來一步步分析。

首先先肯定下這個notifyComplete是在DecodeJob類中,所以callback應該是其成員變量,而後咱們得找出賦值的地方

//重點關注倒數第二個參數,callback的類型爲CallBack
  DecodeJob<R> init( GlideContext glideContext, Object model, EngineKey loadKey, Key signature, int width, int height, Class<?> resourceClass, Class<R> transcodeClass, Priority priority, DiskCacheStrategy diskCacheStrategy, Map<Class<?>, Transformation<?>> transformations, boolean isTransformationRequired, boolean isScaleOnlyOrNoTransform, boolean onlyRetrieveFromCache, Options options, Callback<R> callback, int order) {
    decodeHelper.init(
        glideContext,
        model,
        signature,
        width,
        height,
        diskCacheStrategy,
        resourceClass,
        transcodeClass,
        priority,
        options,
        transformations,
        isTransformationRequired,
        isScaleOnlyOrNoTransform,
        diskCacheProvider);
    this.glideContext = glideContext;
    this.signature = signature;
    this.priority = priority;
    this.loadKey = loadKey;
    this.width = width;
    this.height = height;
    this.diskCacheStrategy = diskCacheStrategy;
    this.onlyRetrieveFromCache = onlyRetrieveFromCache;
    this.options = options;
    this.callback = callback;
    this.order = order;
    this.runReason = RunReason.INITIALIZE;
    this.model = model;
    return this;
  }
複製代碼

很容易的咱們發如今init方法會爲callback賦值,這時候得記住callback參數的具體位置爲倒數第二個。這時候你會想:哪裏會調用DecodeJob的init方法呢?而後揣摩:既然是賦值估計會在構建DecodeJob時候會調用到。因而問題就轉換爲:上文是在哪一個地方構建了DecodeJob?而後內心默唸:DecodeJob是用來執行任務的,因此應該在構建任務的時候會調用!(不過大多數的情形是:腦子裏一片空白,壓根想不出來,反正筆者在這裏就想不出來。因此這時候就能夠直接往上找到DecodeJob首次出現的位置),最終是會在Engine的load中找到DecodeJob的構建

Engine#load

public synchronized <R> LoadStatus load(....){
    //重點關注倒數最後一個參數
	DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);

}
    //重點關注最後一個參數
    <R> DecodeJob<R> build(GlideContext glideContext, Object model, EngineKey loadKey, Key signature, int width, int height, Class<?> resourceClass, Class<R> transcodeClass, Priority priority, DiskCacheStrategy diskCacheStrategy, Map<Class<?>, Transformation<?>> transformations, boolean isTransformationRequired, boolean isScaleOnlyOrNoTransform, boolean onlyRetrieveFromCache, Options options, DecodeJob.Callback<R> callback) {
      DecodeJob<R> result = Preconditions.checkNotNull((DecodeJob<R>) pool.acquire());
      return result.init(
          glideContext,
          model,
          loadKey,
          signature,
          width,
          height,
          resourceClass,
          transcodeClass,
          priority,
          diskCacheStrategy,
          transformations,
          isTransformationRequired,
          isScaleOnlyOrNoTransform,
          onlyRetrieveFromCache,
          options,
          callback,
          creationOrder++);
    }
  }
複製代碼

在上面的代碼中首先調用了DecodeJobFactory的build方法來構建DecodeJob,DecodeJobFactory是Engine的內部類,而後接着看DecodeJobFactory的build方法,哇!跟咱們想的徹底同樣!build方法中調用了DecodeJob的init方法,找到後可別忘了咱們的任務是幹嗎的!找到callback的值,因而看回build的callback的參數位置,在最後一個,而後往回看Engine的load中調用build的最後一個參數!engineJob!沒錯最後找到的callback的類型應該是EngineJob類型的,其實EngineJob是實現了DecodeJob.Callback接口的。因此接下來就會回調EngineJob的onResourceReady方法

EngineJob#onResourceReady

public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    synchronized (this) {
      this.resource = resource;
      this.dataSource = dataSource;
    }
	//重點關注
    notifyCallbacksOfResult();
  }

  void notifyCallbacksOfResult() {
    ResourceCallbacksAndExecutors copy;
    Key localKey;
    EngineResource<?> localResource;
    synchronized (this) {
      ......

	  //重點關注cbs的類型
	  //查找cbs裏面的類型
      copy = cbs.copy();
      .....
    }
    //通知上層Engine的任務完成了
    listener.onEngineJobComplete(this, localKey, localResource);

    for (final ResourceCallbackAndExecutor entry : copy) {
	  //回調給ImageViewTarget來展現資源
      entry.executor.execute(new CallResourceReady(entry.cb));
    }
    decrementPendingCallbacks();
  }
複製代碼

2.6.2 回到主線程

又到了肯定參數類型的時刻了,趕忙召喚福爾摩斯上線!首先咱們先肯定EngineJob的onResourceReady方法中最重要的代碼片

for (final ResourceCallbackAndExecutor entry : copy) {
	  //回調給ImageViewTarget來展現資源
      entry.executor.execute(new CallResourceReady(entry.cb));
    }
複製代碼

在肯定分析線程池的execute的方法前,咱們須要作的事有:

  • 肯定entry.executor類型
  • 肯定entry.cb類型

如今咱們知道entry爲ResourceCallbackAndExecutor方法,因此咱們來看看這個類以及構造器

ResourceCallbackAndExecutor

static final class ResourceCallbackAndExecutor {
    final ResourceCallback cb;
    final Executor executor;

    ResourceCallbackAndExecutor(ResourceCallback cb, Executor executor) {
      this.cb = cb;
      this.executor = executor;
    }
  }
複製代碼

能夠發現executor和cb都是ResourceCallbackAndExecutor中的成員變量,在構造時被賦值,因此咱們須要找到構造ResourceCallbackAndExecutor對象的地方,天然而然咱們會鎖定上面copy這個變量

EngineJob

final ResourceCallbacksAndExecutors cbs = new ResourceCallbacksAndExecutors();

void notifyCallbacksOfResult() {
    ResourceCallbacksAndExecutors copy;
    Key localKey;
    EngineResource<?> localResource;
    synchronized (this) {
      ......

	  //重點關注cbs的類型
	  //查找cbs裏面的類型
      copy = cbs.copy();
      .....
    }
    .....
  }

    ResourceCallbacksAndExecutors copy() {
      return new ResourceCallbacksAndExecutors(new ArrayList<>(callbacksAndExecutors));
    }

     
    //cbs賦值的地方
    synchronized void addCallback(final ResourceCallback cb, Executor callbackExecutor) {
    stateVerifier.throwIfRecycled();
	//此時的cb爲singleRequest類型,其實現了ResourceCallback接口
	//callbackExecutor就是綁定了主線程Handler的線程池
	//cbs的類型爲ResourceCallbacksAndExecutors
	//add的內部實現就是建立ResourceCallbacksAndExecutor並將cb,callbackExecutor賦值到其成員變量
    //而後再add到cbs中 
    cbs.add(cb, callbackExecutor);
    ......
     
  }


    void add(ResourceCallback cb, Executor executor) {
      callbacksAndExecutors.add(new ResourceCallbackAndExecutor(cb, executor));
    }

複製代碼

讓咱們看看copy賦值調用的地方,就是調用了ResourceCallbacksAndExecutors類型的cbs的copy方法,copy其實就是建立了ResourceCallbacksAndExecutor集合,這個集合其實就是cbs,咱們還須要找到cbs賦值的地方,找半天后你會發如今addCallback方法中會找到cbs的add方法,add方法的內部實現其實就是建立ResourceCallbacksAndExecutor並將cb,callbackExecutor賦值到其成員變量中,因此咱們還得肯定add方法的兩個參數是什麼?不知道你是否還有印象,當初在構建任務時咱們有專門提到過這個addCallback方法,讓咱們從新看看Engine的load方法。

Engine#load

....
    //調用addCallback()註冊了一個ResourceCallback
	//這裏的cb是load方法的倒數第二個參數,load是在singleRequest的onSizeReady()調用的
	//查看後cb爲singleRequest類型
	//從新看回EngineJob的addCallback方法
    engineJob.addCallback(cb, callbackExecutor);
	//在子線程中執行DecodeJob的run方法
    engineJob.start(decodeJob);
複製代碼

要想肯定cb和callbackExecutor的類型,咱們還須要一步一步往回走

//特別關注最後兩個參數
  public synchronized <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, Executor callbackExecutor) 複製代碼

SingleRequest#onSizeReady

loadStatus =
    	//重點關注倒數第二個參數,傳入的是this,即SingleRequest對象,其實現了ResourceCallback接口
    	//重點關注倒數第一個參數,傳入有綁定主線程的Handle的r線程池callbackExectuter
        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,
            callbackExecutor);
複製代碼

SingleRequest的onSizeReady中咱們肯定了cb的類型爲SingleRequest對象,另一個參數的話因爲篇幅緣由就不一一貼出代碼了(都是上文貼過的代碼),你能夠直接從onSizeReady方法往回看,上面的註釋也會提到,最後你會發現這個callbackExecutor其實就是咱們一開始提到的含有綁定主線程Handler的線程池。讓咱們回到最初的地方

EngineJob#onResourceReady

for (final ResourceCallbackAndExecutor entry : copy) {
	  //回調給ImageViewTarget來展現資源
       //entry.cb爲singleRequest類型類型
	   //entry.executor就是含有綁定了主線程的Handler的線程池,即MAIN_THREAD_EXECUTOR
      entry.executor.execute(new CallResourceReady(entry.cb));
    }
複製代碼

因此咱們來看看Executors的mainThreadExecutor方法(忘記的從新看上面的2.2)

private static final Executor MAIN_THREAD_EXECUTOR =
      new Executor() {
       //綁定主線程的Looper
        private final Handler handler = new Handler(Looper.getMainLooper());

        @Override
        public void execute(@NonNull Runnable command) {  
          handler.post(command);
        }
      };

public static Executor mainThreadExecutor() {
    return MAIN_THREAD_EXECUTOR;
  }
複製代碼

根據Handler機制的相關知識,當調用MAIN_THREAD_EXECUTOR的execute方法後將會在主線程中執行CallResourceReady對象的run方法。因此咱們看看CallResourceReady的run方法

2.6.3 顯示圖片

EngineJob.CallResourceReady#run

public void run() {
      synchronized (EngineJob.this) {
        if (cbs.contains(cb)) {
          // Acquire for this particular callback.
          engineResource.acquire();
		  //重點關注,此時cb爲SingleRequest對象
          callCallbackOnResourceReady(cb);
          removeCallback(cb);
        }
        decrementPendingCallbacks();
      }
    }
  }

  synchronized void callCallbackOnResourceReady(ResourceCallback cb) {
    try {
      //回調,將目標數據回調出去
      //此時的cb爲singleRequest類型
      cb.onResourceReady(engineResource, dataSource);
    } catch (Throwable t) {
      throw new CallbackException(t);
    }
  }
複製代碼

看到這是否是很開心(實際頭皮發麻)!又來到了咱們熟悉的回調了,此時的cb是SingleRequest類型,咱們已經在上文分析過了。因此會調用SingleRequest的onResourceReady方法

SingleRequest#onResourceReady

public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
    .......
    //重點關注
    onResourceReady((Resource<R>) resource, (R) received, dataSource);
  }

  private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
    //第一次加載
    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");
    }

    isCallingCallbacks = true;
    try {
      boolean anyListenerHandledUpdatingTarget = false;
	  //若是在使用時設置listener的話,就會回調其中的onResourceReady
      if (requestListeners != null) {
        for (RequestListener<R> listener : requestListeners) {
          anyListenerHandledUpdatingTarget |=
              listener.onResourceReady(result, model, target, dataSource, isFirstResource);
        }
      }
      anyListenerHandledUpdatingTarget |=
          targetListener != null
              && targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);
      
      if (!anyListenerHandledUpdatingTarget) {
        Transition<? super R> animation =
            animationFactory.build(dataSource, isFirstResource);

        //展現照片
	    //此時的target爲DrawableImageViewTarget
        target.onResourceReady(result, animation);
      }
    } finally {
      isCallingCallbacks = false;
    }
    //通知加載成功
    notifyLoadSuccess();
  }
複製代碼

這裏咱們只須要關注target.onResourceReady(result, animation)這句代碼,target對象爲DrawableImageViewTarget,因此會調用DrawableImageViewTarget的onResourceReady方法,可是由於DrawableImageViewTarget是沒有onResourceReady這個方法的,因此應該是在其父類ImageViewTarget中

ImageViewTarget

public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
     //是否有動畫效果 
    if (transition == null || !transition.transition(resource, this)) {
	  //重點關注,靜態圖 
      setResourceInternal(resource);
    } else {
      //gif 
      maybeUpdateAnimatable(resource);
    }
  }

  private void setResourceInternal(@Nullable Z resource) {
    //調用setResource來展現照片
    setResource(resource);
    maybeUpdateAnimatable(resource);
  }

  //此方法爲抽象方法,由子類實現,因爲分析的是靜態圖,故實現的子類應該爲DrawableImageViewTarget
  protected abstract void setResource(@Nullable Z resource);
複製代碼

這裏咱們以正常的靜態圖爲例子,因此接下來會調用setResourceInternal(resource)方法,而後繼續調用setResource(resource)方法來展現圖片,setResource在ImageViewTarget爲抽象方法,因此咱們繼續看回子類DrawableImageViewTarget的實現

DrawableImageViewTarget#setResource

protected void setResource(@Nullable Drawable resource) {
    //成功展現照片
    view.setImageDrawable(resource);
  }
複製代碼

哇!看到這裏眼淚估計又要流下來了,沒錯setResource很簡單,就是直接將照片顯示出來!

3. 小結

into方法算的上是整個Glide圖片加載流程中邏輯最複雜的一部曲了,代碼量多,相對應的工做量也是超級多的,既當爹又當媽,既要網絡獲取數據,又要解析並顯示數據。整理後其主要工做以下圖:

總結

Glide源碼閱讀仍是花了很長時間,首先閱讀了幾篇Glide3.x版本的文章和Glide3.7的源碼,而後又閱讀了Glide4.9的文章和源碼,最後再本身總結。閱讀完Glide4.9加載流程的源碼給個人感覺就是這回調是真的多,並且找回調的參數還挺費時間的。不過總體而言,心裏只有一句話,「Glide牛逼!」,用起來只有一行代碼,實際內部處理邏輯是多麼的複雜以及到位,也足以見得Glide的功能有多強大了。可是Glide功能的強大不只僅體如今圖片加載流程,還有其強大的緩存策略,讓咱們繼續領略Glide的強大: Glide 4.9源碼解析-緩存策略

參考博客:

相關文章
相關標籤/搜索