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


寫在之前

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

正文

Glide的使用和Picasso基本一樣,這里就不再多說,主要是因為源碼分析會寫的很長很細,再加上基本使用的話,就更加長了,而且上一篇已寫過Picasso的基本使用,這兩者在使用方面相差的微乎及微,所以我們這篇文章直接進入源碼分析。

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方法的源碼:

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,今天就先發布這一篇吧。

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

同時,請大家掃一掃關注我的微信公眾號,雖然寫的不是很勤,但是每一篇都有質量保證,讓您學習到真正的知識。

關注我的微信公眾號


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM