Android圖片加載庫Glide 知其然知其因此然 開篇

前言

我以爲使用第三方的庫時,要作到 知其然 知其因此然 欲然革之 棄之天然 好吧不裝x了說人話就是,對一個庫的瞭解程度能夠化爲爲這樣幾個等級:緩存

  • 首先,要可以熟練使用它。
  • 而後,理解其中的原理,怎麼實現的,思考爲何這樣實現
  • 再而後,在瞭解原理的基礎上,若是想要實現庫自己不支持的功能或者感受實現的很差,這樣會狀況下可以改造它。
  • 最後,會用,原理懂了,能遊刃有餘的更改,還以爲本身的才華得不到施展,那就能夠其之天然,也就是本身造輪子。 接下來,第一個階段就先跳過了,跳級進入第二個階段。拆輪子,探一探Glide這個庫時怎麼實現的。

總體Glide是怎樣架構的,大輪子如何轉動起來,經過這篇文章對Glide的總體有個認識而後逐一突破。 (這圖畫我了倆小時....,手動比心,求贊) bash

一、關於Glide的建立

Glide的簡單使用是下面這樣的:網絡

Glide.with(context).load("http:xxxx").into(target) 
複製代碼

先看看Glide.with()方法作了什麼。Glide的with(x)方法的參數能夠是:Context、Activity、Fragment、View。 不管是哪一種參數都會直接或者間接的調用下面這個方法:架構

private static RequestManagerRetriever getRetriever(@Nullable Context context){
    Preconditions.checkNotNull(context,"..");
    return Glide.get(context).getRequestManagerRetriever();
}
複製代碼

這個方法最終會返回一個RequestManagerRetriever對象。Glide.get(ctx)返回的是一個Glide對象,內部使用的單例模式,進程內Glide是單例,以下。敲黑板,這不就是傳說中的雙重效驗鎖。app

@NonNull
  public static Glide get(@NonNull Context context) {
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context);
        }
      }
    }
    return glide;
  }
複製代碼

找到了Glide建立的地方,Glide.get(ctx)->checkAndInitializeGlide(ctx)->initializeGlide(ctx,glideBuilder),最終建立glide單例對象的重擔落在了initializeGlide(..)方法上ide

private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
    Context applicationContext = context.getApplicationContext();
    GeneratedAppGlideModule annotationGeneratedModulegetAnnotationGeneratedGlideModules();
    ....
    Glide glide = builder.build(applicationContext);
    ...
    applicationContext.registerComponentCallbacks(glide);
    Glide.glide = glide;
  }
複製代碼

咱們源碼中關於使用APT技術動態加載GeneratedAppGlideModule對象而後配置Glide相關代碼隱去了,篇幅有限這一部分單獨成篇詳細探究。ui

先看這個方法主要完成了三件事:this

  • 使用APT技術動態加載GeneratedAppGlideModule對象而後配置Glide。(之後探其究竟)
  • 使用構造者模式GlideBuilder建立了了Glide對象
  • applicationContext.registerComponentCallbacks(glide),applicationContext註冊了ComponentCallbacks監聽,這裏傳入的上一步中新鮮建立的glide對象,glide實現了ComponentCallbacks2接口,接口中void onTrimMemory(@TrimMemoryLevel int level);的方法會在操做系統內存不足的時候會調用,咱們能想到這是清理緩存的好時機。

建立小結

image

# GlideBuild
 Glide build(@NonNull Context context) {
    if (sourceExecutor == null) {...}
    if (diskCacheExecutor == null) {...}
    if (animationExecutor == null) {...}
    ...
    if (memoryCache == null) {...}
    if (diskCacheFactory == null) {...}
    if (engine == null) {...}
    return new Glide(context, engine,memoryCache,bitmapPool,arrayPool...)
  }
複製代碼

如上圖通過層層最終調用initializeGlide(),這個方法中使用GlideBuilder對象夠建出Glide對象,值得關注的是他是一個單例。並且當在GlideBuider沒有設置響應參數的時候會生成默認的參數供GlideBuilder建立出Glide對象。spa

二、關於請求管理

2.一、RequestManagerRetriever

書接上回,咱們已經對Glide這個類的建立有了一個大致的認知。操作系統

仍是那行代碼,

RequestManager requestManager = Glide.with(this);
複製代碼

這行代碼順序的作了三件事

  • 一、經過Glide glide = Glide.get(context)最終建立獲得了一個Glide單例對象;
  • 二、調用glide.getRetriever()獲得requestManagerRetriever對象
  • 三、RequestManager manager = requestManagerRetriever.getRequestManager(context)獲得一個RequestManager的對象。

RequestManagerReriever類的註釋

A collection of static methods for creating new RequestManagers or retrieving existing ones from activities and fragment.

這個類的職責就是建立新的RequestManager或者在activity和fragment中檢索出已經存在的。

建立一個RequestManager的資料中很重要的一個就是LifeCycle

  • 有兩個類實現了LifeCycle分別是ActivityFragmentLifecycle和ApplicationLifecycle。主要區別就在於,ActivityFragmentLifecycle有感知Fragment/Activity聲明週期的能力。
  • 若是傳入的是Fragment或者Acitivy,requestManagerReriever視圖建立一個RequestManagerFragment對象,與其綁定,這樣就實現了對Activity,或者Fragment聲明週期的感知。
  • 若是傳入的是ApplicationContext就會傳入有兩個類實現了LifeCycle分別是ActivityFragmentLifecycle和ApplicationLifecycle。

摘了比較核心的一段代碼標記,加了註釋。

private RequestManager fragmentGet(@NonNull Context context,FragmentManager fm,Fragment parentHint,boolean isParentVisible) {
    //獲取一個RequestManagerFragment
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
    //試圖在RequestManagerFragment中獲取requestManager
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
    //若是爲空就建立一個而且存到RequestManagerFragment中
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }
複製代碼

注意的點

  • RequestManagerReriever何時建立的呢?在GlideBuilder中build方法中new了一個經過Glide的構造方法傳入的。
  • 當RequestManagerReriever.get(view)的時候,會查找view所在的Activity進而去創建立Requestmanager,若是沒有找到所在Activity就使用ApplicationLifecycle構建Requestmanager。

總結下RequestManagerReriever對象建立RequestManager流程。

image

2.2 RequestManager、RequestBuilder

RequestManager見名知意,管理圖片請求,啓動、暫停、從新啓動請求,依據所在組件的生命週期週期和網絡作出恰當的動做

使用RequestManager對象一系列的load()方法最終可以獲得一個RequestBuilder的對象, RequestBuilder是一個泛型類,加載什麼樣的類型圖片資源決定了他是什麼類型,圖片資源的來源多是Recource、File、或者網絡。

RequestBuilder<T> requestBuidlder = requestManager.load(xxxx);
複製代碼

獲得RequestBuilder以後,就能夠對請求的圖片資源作一些指望設置

  • 好比你但願他是多大的,指定尺寸:override()。
  • 但願它使用什麼樣子的裁剪規則:centerCrop(),centerInside();..
  • 指望他的緩存的機制是怎樣的:diskCacheStrategy()。

RequestBuildler,均可以經過RequestOptions進行配置。ReuqestBuilder繼承了BaseRequestOptions類,BaseRequestOption這個類是鏈接RequestOption和RequestBuilder的橋樑,經過這個類的對象對RequestOption進行一系列的設置。

Request有三個實現類,RequestCoordinator,SingleRequest和ErrorRequestCoordinator,RequestCoodinator。

  • RequestCoordinator中包含兩個Request,一個是 primary, error。RequestCoordinator使用primary發起請求,若是primary請求失敗了,就調用error請求。
  • SingleReuqest 實現了Request方法,加載來自不一樣類型的圖片資源。
  • ThumbnailRequestCoordinator 同時加載縮略圖和原始圖。

#RequestBuilder 構建ErrorRequestCoordinator對象的方法爲例。

private Request buildRequestRecursive(..) {
    //構建請求控制
    ErrorRequestCoordinator errorRequestCoordinator = null;
    if (errorBuilder != null) {
      errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }
    //構建的主請求
    Request mainRequest =(...);
    if (errorRequestCoordinator == null) {
      return mainRequest;
    }

    int errorOverrideWidth = errorBuilder.getOverrideWidth();
    int errorOverrideHeight = errorBuilder.getOverrideHeight();
    if (Util.isValidDimensions(overrideWidth, overrideHeight)
        && !errorBuilder.isValidOverride()) {
      errorOverrideWidth = requestOptions.getOverrideWidth();
      errorOverrideHeight = requestOptions.getOverrideHeight();
    }
    //構建錯誤請求
    Request errorRequest =
        errorBuilder.buildRequestRecursive(..);
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }
複製代碼

整個Request構建管理的構成以下

這只是一個總體的流程,關於更詳細的Request管理,包括若是感知聲明週期的,重複請求如何管理,參數設置的原理等等單獨成篇分析。

三、Engine

Request對象的begin()方法根據圖片不一樣的來源去加載,獲取到指望尺寸以後就會調用onSizeReady(),傳入一系列參數信息。

onSizeReady(){
...
    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,
        callbackExecutor);
...
}

複製代碼

engin.load()

public synchronized <R> LoadStatus load(...) {
    ...
    EngineJob<R> engineJob =engineJobFactory.build(...);
    DecodeJob<R> decodeJob =decodeJobFactory.build(...);
    ...
    engineJob.addCallback(cb, callbackExecutor);//加載
    engineJob.start(decodeJob);//解碼,對二進制數據轉換成圖片根據配置進行編輯
    ...
    return new LoadStatus(cb, engineJob);
  }
複製代碼

EngineJob.load實際加載圖片數據的執行者,加載完以後交給decodeJob處理。內部具體如何實現的單獨成篇分析,如這部分中線程池如何使用,Bitmap的使用技巧等。

以上對Glide這個優秀的開源庫有了一個總體的認識,大致分爲三個部分

  • Glide建立
  • Request管理
  • 加載解析 咱們會單獨成篇嗎,還可能會把緩存策略的應用縱向進行分析。最後再把我花了兩個小時的總體架構圖放上
    image
相關文章
相關標籤/搜索