Android 圖片加載框架Glide4.0源碼徹底解析(一)

寫在以前html

上一篇博文寫的是Picasso基本使用和源碼徹底解析,Picasso的源碼閱讀起來仍是很順暢的,而後就想到Glide框架,網上你們也都推薦使用這個框架用來加載圖片,正好我目前的寫做目標也是分析當前一些流行的框架源碼,那就也來解析下Glide的源碼吧,並且有了Picasso源碼的分析相信很快就搞定Glide的,結果也就悲劇了,深陷其中沒法自拔了,Glide的源碼遠非Picasso能比,閱讀起來也是至關的困難的,並且我使用的是最新的Glide4.0,與以前版本有較大的差別,網上也沒能夠參考的資料,這就悲劇了,苦頭專研唄。直到今天才從深溝中冒出頭了,差點憋死,哈哈。python

正文git

Glide的使用和Picasso基本同樣,這裏就再也不多說,主要是由於源碼分析會寫的很長很細,再加上基本使用的話,就更加長了,並且上一篇已寫過Picasso的基本使用,這二者在使用方面相差的微乎及微,因此咱們這篇文章直接進入源碼分析。github

Glide 源碼分析

首先在build.gradle裏添加以下引用:設計模式

compile 'com.github.bumptech.glide:glide:4.0.0-RC0'

這裏我用的是Glide4.0也是最新的版本,和3.X在源碼上仍是有很大的差異的。看過3.X源碼的相信對比下這篇文章就會知道。緩存

ok,和Picasso的分析模式同樣,咱們也是從下面最簡單的代碼進行一步一步的深刻分析:微信

Glide.with(MainActivity.this).load(url).into(headerImage);

with()

首先咱們來看看當咱們調用Glide的with方法那作了哪些工做:網絡

with方法中能夠接受Context,Activity,FragmentActivity,Fragment甚至是View不一樣的類型,返回的是RequestManager對象,這個對象是須要在RequestManagerRetriever中獲取的,那咱們在來看看RequestManagerRetriever是怎麼獲取到的?請看getRetriever方法的源碼:app

getRetriever方法中也沒有真正的建立RequestManagerRetriever對象,而是從Glide的getRequestManagerRetriever方法中獲取,那麼很明顯的能夠看出所作的工做都是在Glide的get方法中完成的,在來看下get方法源碼:框架

來到這一步,咱們看到了很是熟悉的代碼設計原理,那就是雙重加鎖的單例模式保證Glide對象的惟一性,那麼initGlide就是建立Glide對象的方法了,請看:

這是initGlide方法中最重要的代碼,主要是建立了一個GlideBuilder對象,而後調用build方法來完成Glide對象的建立,相信不用看bulid方法,你們也會猜到接下來將要發生什麼樣的事情,沒錯,那就是使用建造者設計模式來完美的構建出Glide對象:

public Glide build(Context context) {
    if (sourceExecutor == null) {
      sourceExecutor = GlideExecutor.newSourceExecutor();
    }

    if (diskCacheExecutor == null) {
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    }

    if (memorySizeCalculator == null) {
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    }

    if (connectivityMonitorFactory == null) {
      connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
    }

    if (bitmapPool == null) {
      int size = memorySizeCalculator.getBitmapPoolSize();
      bitmapPool = new LruBitmapPool(size);
    }

    if (arrayPool == null) {
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }

    if (memoryCache == null) {
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }

    if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }

    if (engine == null) {
      engine = new Engine(memoryCache, diskCacheFactory, diskCacheExecutor, sourceExecutor,
          GlideExecutor.newUnlimitedSourceExecutor());
    }

    RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(
        requestManagerFactory);

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock());
  }

build方法中主要是構建線程池(包括sourceExecutor ,diskCacheExecutor ),緩存大小和緩存器,默認的鏈接監聽工廠(connectivityMonitorFactory ),Engine對象和RequestManagerRetriever 對象等等。

有幾個重要的對象建立,咱們這裏先看下它的構建內容:

1 Engine對象

建立Engine對象在構造方法中傳遞了幾個重要的參數,分別是線程池,內存緩存和硬盤緩存對象,那咱們來看看在構造方法中它是怎麼構建Engine對象的:

Engine(MemoryCache cache,
      DiskCache.Factory diskCacheFactory,
      GlideExecutor diskCacheExecutor,
      GlideExecutor sourceExecutor,
      GlideExecutor sourceUnlimitedExecutor,
      Map<Key, EngineJob<?>> jobs,
      EngineKeyFactory keyFactory,
      Map<Key, WeakReference<EngineResource<?>>> activeResources,
      EngineJobFactory engineJobFactory,
      DecodeJobFactory decodeJobFactory,
      ResourceRecycler resourceRecycler) {
    this.cache = cache;
    this.diskCacheProvider = new LazyDiskCacheProvider(diskCacheFactory);

    if (activeResources == null) {
      activeResources = new HashMap<>();
    }
    this.activeResources = activeResources;

    if (keyFactory == null) {
      keyFactory = new EngineKeyFactory();
    }
    this.keyFactory = keyFactory;

    if (jobs == null) {
      jobs = new HashMap<>();
    }
    this.jobs = jobs;

    if (engineJobFactory == null) {
      engineJobFactory = new EngineJobFactory(diskCacheExecutor, sourceExecutor,
          sourceUnlimitedExecutor, this);
    }
    this.engineJobFactory = engineJobFactory;

    if (decodeJobFactory == null) {
      decodeJobFactory = new DecodeJobFactory(diskCacheProvider);
    }
    this.decodeJobFactory = decodeJobFactory;

    if (resourceRecycler == null) {
      resourceRecycler = new ResourceRecycler();
    }
    this.resourceRecycler = resourceRecycler;

    cache.setResourceRemovedListener(this);
  }

建立了幾個工廠對象方法,好比EngineKeyFactory,EngineJobFactory和DecodeJobFactory,幾個HashMap類型的對象集合,如:jobs ,activeResources 等等,而後就分別把這些對象賦值給Engine的成員變量,那麼來看下建立Engine對象時到底初始化了那些成員變量:

ok,Engine是一個很是重要的對象,後面扮演着重要的角色,爲了方面理解它所擁有那些可以使用的對象,這裏我作了個類圖顯示的標了出來。

2 RequestManagerRetriever 對象

再來看看RequestManagerRetriever 對象的建立,這個相對的簡單不少,咱們來看下它的構造方法:

因爲咱們傳遞過來的requestManagerFactory爲空,因此factory將會使用默認的DEFAULT_FACTORY工廠,DEFAULT_FACTORY是真正建立RequestManager對象的地方,稍後介紹。

這裏只是讓你們知道這裏的factory就是DEFAULT_FACTORY。

來看看它擁有哪些成員:

3 Glide對象

在build方法中 return new Gilde(),建立一個Glide對象並返回,那在Gilde構造方法中作了哪些初始化工做呢?

Glide(
      Context context,
      Engine engine,
      MemoryCache memoryCache,
      BitmapPool bitmapPool,
      ArrayPool arrayPool,
      RequestManagerRetriever requestManagerRetriever,
      ConnectivityMonitorFactory connectivityMonitorFactory,
      int logLevel,
      RequestOptions defaultRequestOptions) {
    this.engine = engine;
    this.bitmapPool = bitmapPool;
    this.arrayPool = arrayPool;
    this.memoryCache = memoryCache;
    this.requestManagerRetriever = requestManagerRetriever;
    this.connectivityMonitorFactory = connectivityMonitorFactory;

    DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT);
    bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);

    final Resources resources = context.getResources();

    registry = new Registry();
    registry.register(new DefaultImageHeaderParser());

    registry.register()...append()...

    ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
    glideContext = new GlideContext(context, registry, imageViewTargetFactory,
        defaultRequestOptions, engine, this, logLevel);
  }

這裏首先是把傳遞進來的參數賦值給成員變量,而後建立了幾個重要的對象:

①:Registry對象

Registry主要是添加不少的註冊或解析方式等,這在後面用來解析是從內存,文件或是網絡獲取資源有着重要的做用,並且它每一類解析方式都會提供多個方法,一種方式獲取不到將會使用另一種,知道獲取到資源爲止,來看下它的register和append方法:

主要是存放到不一樣的對象中的集合變量中。

②:GlideContext對象

GlideContext對象在後面也扮演中重要的角色,建立這個對象到目前爲止只是爲了初始化和賦值:

總結下Glide,Registry和GlideContext對象所初始化的參數:

這是到目前對象所擁有的成員方法和成員變量。

ok,再回到上面build方法,在返回Glide對象後,調用getRequestManagerRetriever()從而獲取到RequestManagerRetriever對象,從上面Glide類圖咱們也能夠看出,Glide對象已包含RequestManagerRetriever對象。

再往上返回一步,在getRetriever(activity)方法中獲取到RequestManagerRetriever對象後,調用get(activity)來獲取RequestManager對象,那麼咱們來看看它是怎麼獲取到的?

首先判斷是否在子線程執行,不然就調用supportFragmentGet方法來獲取RequestManager對象,那麼來看下它的源碼:

還記得咱們的RequestManagerRetriever擁有哪些成員嗎,不記得就去看看上面它的類圖吧,由它的源碼咱們能夠看到它將會使用factory並調用它的build方法,還記得factory是什麼嗎?上面已分析factory就是DEFAULT_FACTORY,那來看看它的源碼實現:

在build中建立一個RequestManager對象並返回,來看下RequestManager的構造方法中作了哪些操做:

RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory) {
    this.glide = glide;
    this.lifecycle = lifecycle;
    this.treeNode = treeNode;
    this.requestTracker = requestTracker;

    final Context context = glide.getGlideContext().getBaseContext();

    connectivityMonitor =
        factory.build(context, new RequestManagerConnectivityListener(requestTracker));

    if (Util.isOnBackgroundThread()) {
      mainHandler.post(addSelfToLifecycle);
    } else {
      lifecycle.addListener(this);
    }
    lifecycle.addListener(connectivityMonitor);

    setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());

    glide.registerRequestManager(this);
  }

主要是賦值,添加生命週期監聽器,設置請求屬性,以及註冊請求管理器,代碼仍是很簡單的,都能看的明白。

來看下它的類圖:

ok,到此,咱們的with方法中獲取RequestManager對象就已完成。

來看下with方法執行的順序圖:

注:流程圖看不清楚,能夠選擇在「新標籤中打開圖片」查看。

load()

在調用with方法獲取到RequestManager對象的前提下,調用load方法,並傳遞咱們的url參數,來看下它的源碼:

這裏並無直接的去加載咱們的url獲取資源,而是首先調用asDrawable方法來配置圖片的信息,其實就是說加載獲取的圖片資源是轉換爲drawale或是bitmap或是gif進行圖片顯示,默認的是使用drawale,你也可使用asGif()/asBitmap()來設置它是已什麼形式來展現。這裏咱們按默認的方式來分析。

load方法目的是爲了獲取RequestBuilder對象,下面來一步步分解它源碼:

首先來看下asDrawable()的源碼:

asDrawable()中首先調用as方法,並傳進Drawable.class做爲參數,來看下as方法的源碼:

由as方法,咱們可看到它直接的建立一個RequestBuilder對象,並傳遞了相關的參數進去,這裏要注意下resourceClass就是Drawable.class這裏在後面有個選擇分支時使用到。

來看下RequestBuilder的構造方法中作了哪些初始化佈局。

很簡單的賦值,這裏也須要注意的是transcodeClass就是Drawable.class類。

ok,獲取到RequestBuilder對象後,它又作了進一步的賦值操做,就是在transition方法中,

把建立的DrawableTransitionOptions對象賦值給transitionOptions變量。

ok,再往上來看,完成asDrawable方法對RequestBuilder的建立後才調用load方法來傳遞咱們的url地址,其實在load也沒有作什麼事,就是一箇中轉站,轉給了loadGeneric方法,來看:

在loadGeneric方法中也沒作其餘太多的操做,也是保存了咱們的url而且isModelSet設置爲true,意思就是說Model已有設置了。來看下它的類圖:

它到目前爲止所包含的成員變量和方法都在此。

ok,到此咱們的load方法也分析完畢,來看下它的流程圖:

注:流程圖看不清楚,能夠選擇在「新標籤中打開圖片」查看。

因爲Glide源碼非常複雜,寫的很長,因此只能分兩篇來發布,第一篇分析了Glide的with和load方法源碼,第二篇將會分析into方法,說實在的into方法複雜程度遠超過with和load方法總和,可是不要緊,仍是保持一向的風格,一步步的分析其執行流程,相信你們學完確定能徹底的掌握它的源碼結構。

ok,今天就先發布這一篇吧。

各位若是還有哪裏不明白的,或是我這裏講的還不夠透徹,亦或是講錯了的地方請留言指正,讓咱們共同進步,謝謝

同時,請你們掃一掃關注個人微信公衆號,雖然寫的不是很勤,可是每一篇都有質量保證,讓您學習到真正的知識。

關注個人微信公衆號

相關文章
相關標籤/搜索