Glide 源碼分析

###1. 功能介紹
圖片加載框架,相對於UniversalImageLoader,Picasso,它還支持video,Gif,SVG格式,支持縮略圖請求,旨在打造更好的列表圖片滑動體驗。Glide有生命週期的概念(主要是對請求進行pause,resume,clear),而且其生命週期與Activity/Fragment的生命週期綁定,支持Volley,OkHttp,並提供了相應的integration libraries,內存方面也更加友好。

###2. 總體設計

####2.1 總體設計圖

####2.2 Glide中的概念

Glide
使用RequestBuilder創建request的靜態接口,並持有Engine,BitmapPool,DiskCache,MemoryCache。
實現了ComponentCallbacks2,註冊了低內存情況的回調。當內存不足的時候,進行相應的內存清理。回調的發生在RequestManagerFragment的onLowMemory和onTrimMemory中。
更詳細的介紹可參考4.2.1 Glide

GlideBuilder
爲Glide設置一些默認配置,比如:Engine,MemoryCache,DiskCache,RequestOptions,GlideExecutor,MemorySizeCalculator

GlideModule
可以通過GlideBuilder進行一些延遲的配置和ModelLoaders的註冊。

注意:
所有的實現的module必須是public的,並且只擁有一個空的構造函數,以便Glide懶加載的時候可以通過反射調用。
GlideModule是不能指定調用順序的。因此在創建多個GlideModule的時候,要注意不同Module之間的setting不要衝突了。
如何創建Module,請參看Demo

Engine
負責任務創建,發起,回調,資源的管理
詳細介紹請參考4.2.3 Engine

DecodeJob
調度任務的核心類,整個請求的繁重工作都在這裏完成,處理來自緩存或者原始的資源,應用轉換動畫以及transcode。
詳細介紹請參考4.2.5 DecodeJob

ModelLoader
各種資源的ModelLoader

該接口有兩個目的:

  • 將任意複雜的model轉換爲可以被decode的數據類型
  • 允許model結合View的尺寸獲取特定大小的資源

更詳細的介紹請參考 4.2.19 ModelLoader

Resource
對資源進行包裝的接口,提供get,recycle,getSize,以及原始類的getResourceClass方法。
resource包下也就是各種資源:bitmap,bytes,drawable,file,gif,以及相關解碼器,轉換器

Target
request的載體,各種資源對應的加載類,含有生命週期的回調方法,方便開發人員進行相應的準備以及資源回收工作。

ThumbnailRequestCoordinator
請求協調器,包含兩個請求:縮略圖請求+完整圖片請求

數據相關概念

  • data :代表原始的,未修改過的資源,對應dataClass
  • resource : 修改過的資源,對應resourceClass
  • transcoder : 資源轉換器,比如 BitmapBytesTranscoder(Bitmap轉換爲Bytes),GifDrawableBytesTranscoder
  • ResourceEncoder : 持久化數據的接口,注意,該類並不與decoder相對應,而是用於本地緩存的接口
  • ResourceDecoder : 數據解碼器,比如ByteBufferGifDecoder(將ByteBuffer轉換爲Gif),StreamBitmapDecoder(Stream轉換爲Bitmap)
  • ResourceTranscoder : 資源轉換器,將給定的資源類型,轉換爲另一種資源類型,比如將Bitmap轉換爲Drawable,Bitmap轉換爲Bytes
  • Transformation : 比如對圖片進行FitCenter,CircleCrop,CenterCrop的transformation,或者根據給定寬高對Bitmap進行處理的BitmapDrawableTransformation

Registry
對Glide所支持的Encoder ,Decoder ,Transcoder組件進行註冊
因爲Glide所支持的數據類型太多,把每一種的數據類型及相應處理方式的組合形象化爲一種組件的概念。通過registry的方式管理。
如下,註冊了將使用BitmapDrawableTranscoder將 Bitmap轉換爲BitmapDrawable的組件。


1

Registry.register(Bitmap.class, BitmapDrawable.class,new BitmapDrawableTranscoder(resources, bitmapPool))

關於Decoder,Transcoder和Registry的詳細介紹請參考4.2.18 Registry

###3. 流程圖

###4. 詳細設計

####4.1 類關係圖

####4.2 類詳細介紹

#####4.2.1 Glide
向外暴露單例靜態接口,構建Request,配置資源類型,緩存策略,圖片處理等,可以直接通過該類完整簡單的圖片請求和填充。內存持有一些內存變量BitmapPoolMemoryCacheByteArrayPool,便於低內存情況時自動清理內存。

#####4.2.2 RequestBuilder
創建請求,資源類型配置,縮略圖配置,以及通過BaseRequestOptions進行一些默認圖,圖片處理的配置

主要函數
(1) thumbnail(@Nullable RequestBuilder thumbnailRequest)
配置縮略圖的請求,如果配置的縮略圖請求在完整的圖片請求完成前回調,那麼該縮略圖會展示,如果在完整請求之後,那麼縮略圖就無效。Glide不會保證縮略圖請求和完整圖片請求的順序。

(2) 多個load重載的方法
指定加載的數據類型
load(@Nullable Object model)
load(@Nullable String string)
load(@Nullable Uri uri)
load(@Nullable File file)
load(@Nullable Integer resourceId)
load(@Nullable URL url)
load(@Nullable byte[] model)

(3) buildRequest(Target target)
創建請求,如果配置了thumbnail(縮略圖)請求,則構建一個ThumbnailRequestCoordinator(包含了FullRequest和ThumbnailRequest)請求,否則簡單的構建一個Request。

(4) into(Y target)
設置資源的Target,並創建,綁定,跟蹤,發起請求

整個請求的創建流程圖

###4.2.3 Engine
任務創建,發起,回調,管理存活和緩存的資源

主要函數

(1) loadFromCache(Key key, boolean isMemoryCacheable)
從內存緩存中獲取資源,獲取成功後會放入到activeResources中

(2) loadFromActiveResources
從存活的資源中加載資源,資源加載完成後,再將這個緩存數據放到一個 value 爲軟引用的 activeResources map 中,並計數引用數,在圖片加載完成後進行判斷,如果引用計數爲空則回收掉。

(3) getReferenceQueue
activeResources是一個持有緩存WeakReference的Map集合。ReferenceQueue就是提供資源WeakReference的虛引用隊列。
activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
這裏要提的是負責清除WeakReference被回收的activeResources資源的實現:
使用到了MessageQueue.IdleHandler,源碼的註釋:當一個線程等待更多message的時候會觸發該回調,就是messageQuene空閒的時候會觸發該回調



/**
* Callback interface for discovering when a thread is going to block
* waiting for more messages.
*/
public static interface IdleHandler {
/**
* Called when the message queue has run out of messages and will now
* wait for more. Return true to keep your idle handler active, false
* to have it removed. This may be called if there are still messages
* pending in the queue, but they are all scheduled to be dispatched
* after the current time.
*/
boolean queueIdle();
}
resourceReferenceQueue = new ReferenceQueue<>();
MessageQueue queue = Looper.myQueue();
queue.addIdleHandler(new RefQueueIdleHandler(activeResources, resourceReferenceQueue));

RefQueueIdleHandler實現了MessageQueue.IdleHandler接口,該接口有一個queueIdle方法,負責清除WeakReference被回收的activeResources資源。

(4) load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
Options options,
boolean isMemoryCacheable,
ResourceCallback cb)

真正的開始加載資源,看下面的流程圖

load調用處理流程圖:
注:DecodeJob是整個任務的核心部分,在下面DecodeJob中有詳細介紹,這裏主要整個流程

###4.2.4 EngineJob
調度DecodeJob,添加,移除資源回調,並notify回調

####主要方法
(1)start(DecodeJob decodeJob)
調度一個DecodeJob任務

(2) MainThreadCallback
實現了Handler.Callback接口,用於Engine任務完成時回調主線程

###4.2.5 DecodeJob
實現了Runnable接口,調度任務的核心類,整個請求的繁重工作都在這裏完成:處理來自緩存或者原始的資源,應用轉換動畫以及transcode。
負責根據緩存類型獲取不同的Generator加載數據,數據加載成功後回調DecodeJob的onDataFetcherReady方法對資源進行處理

####主要方法

(1) runWrapped()
根據不同的runReason執行不同的任務,共兩種任務類型:

  • runGenerators():load數據
  • decodeFromRetrievedData():處理已經load到的數據

RunReason
再次執行任務的原因,三種枚舉值:

  • INITIALIZE:第一次調度任務
  • WITCH_TO_SOURCE_SERVICE:本地緩存策略失敗,嘗試重新獲取數據,兩種情況;當stage爲Stage.SOURCE,或者獲取數據失敗並且執行和回調發生在了不同的線程
  • DECODE_DATA:獲取數據成功,但執行和回調不在同一線程,希望回到自己的線程去處理數據

(2) getNextStage
獲取下一步執行的策略,一共5種策略:
INITIALIZERESOURCE_CACHEDATA_CACHESOURCEFINISHED

其中加載數據的策略有三種:
RESOURCE_CACHEDATA_CACHESOURCE
分別對應的Generator:

  • ResourceCacheGenerator :嘗試從修改過的資源緩存中獲取,如果緩存未命中,嘗試從DATA_CACHE中獲取
  • DataCacheGenerator 嘗試從未修改過的本地緩存中獲取數據,如果緩存未命中則嘗試從SourceGenerator中獲取
  • SourceGenerator 從原始的資源中獲取,可能是服務器,也可能是本地的一些原始資源

策略的配置在DiskCacheStrategy。開發者可通過BaseRequestOptions設置:

  • ALL
  • NONE
  • DATA
  • RESOURCE
  • AUTOMATIC(默認方式,依賴於DataFetcher的數據源和ResourceEncoder的EncodeStrategy)

(3) getNextGenerator
根據Stage獲取到相應的Generator後會執行currentGenerator.startNext(),如果中途startNext返回true,則直接回調,否則最終會得到SOURCE的stage,重新調度任務

(4) startNext
從當前策略對應的Generator獲取數據,數據獲取成功則回調DecodeJob的onDataFetcherReady對資源進行處理。否則嘗試從下一個策略的Generator獲取數據。

(5) reschedule
重新調度當前任務

(6) decodeFromRetrievedData
獲取數據成功後,進行處理,內部調用的是runLoadPath(Data data, DataSource dataSource,LoadPath<Data, ResourceType, R> path)

(7) DecodeCallback.onResourceDecoded
decode完成後的回調,對decode的資源進行transform
path.load(rewinder, options, width, height,
new DecodeCallback(dataSource));

數據加載流程圖

####4.2.6 LoadPath
根據給定的數據類型的DataFetcher嘗試獲取數據,然後嘗試通過一個或多個decodePath進行decode。

####4.2.7 DecodePath
根據指定的數據類型對resource進行decode和transcode

####4.2.8 RequestTracker
追蹤,取消,重啓失敗,正在處理或者已經完成的請求

重要方法

(1) resumeRequests
重啓所有未完成或者失敗的請求,Activity/Fragment的生命週期onStart的時候,會觸發RequestManager調用該方法

(2) pauseRequests
停止所有的請求,Activity/Fragment的生命週期onStop的時候,會觸發RequestManager調用該方法。

(3) clearRequests
取消所有的請求並清理它們的資源,Activity/Fragment的生命週期onDestory的時候,會觸發RequestManager調用該方法。

(4) restartRequests
重啓失敗的請求,取消並重新啓動進行中的請求,網絡重新連接的時候,會調用該方法重啓請求。

(5) clearRemoveAndRecycle
停止追蹤指定的請求,清理,回收相關資源。

####4.2.9 TargetTracker
持有當前所有存活的Target,並觸發Target相應的生命週期方法。方便開發者在整個請求過程的不同狀態中進行回調,做相應的處理。

####4.2.10 RequestManager
核心類之一,用於Glide管理請求。
可通過Activity/Fragment/Connectivity(網絡連接監聽器)的生命週期方法進行stop,start和restart請求。

重要方法
(1) resumeRequests

在onStart方法中調用,其實是通過requestTracker處理,同時也會調用targetTracker.onStart();回調Target相應週期方法。

(2) pauseRequests
在onStop方法中調用,其實是通過requestTracker處理,同時也會調用targetTracker.onStop();回調Target相應週期方法

(3) onDestroy
調用targetTracker.onDestroy();requestTracker.clearRequests();lifecycle.removeListener(this);等進行資源清理。

(4) resumeRequestsRecursive
遞歸重啓所有RequestManager下的所有request。在Glide中源碼中沒有用到,暴露給開發者的接口。

(5) pauseRequestsRecursive
遞歸所有childFragments的RequestManager的pauseRequest方法。同樣也只是暴露給開發者的接口。
childFragments表示那些依賴當前Activity或者Fragment的所有fragments

  • 如果當前Context是Activity,那麼依附它的所有fragments的請求都會中止
  • 如果當前Context是Fragment,那麼依附它的所有childFragment的請求都會中止
  • 如果當前的Context是ApplicationContext,或者當前的Fragment處於detached狀態,那麼只有當前的RequestManager的請求會被中止

注意:
在Android 4.2 AP17之前,如果當前的context是Fragment(當fragment的parent如果是activity,fragment.getParentFragment()直接返回null),那麼它的childFragment的請求並不會被中止。原因是在4.2之前系統不允許獲取parent fragment,因此不能確定其parentFragment。 但v4的support Fragment是可以的,因爲v4包的Fragment對應的SupportRequestManagerFragment提供了一個parentFragmentHint,它相當於Fragment的ParentFragment。在RequestManagerRetriever.get(support.V4.Fragment fragment)的時候將參數fragment作爲parentFragmentHint。

(6) registerFragmentWithRoot
獲取Activity相應的RequestManagerFragment,並添加到Activity的事務當中去,同時將當前的Fragment添加到childRequestManagerFragments的HashSet集合中去,以便在pauseRequestsRecursiveresumeRequestsRecursive方法中調用RequestManagerTreeNode.getDescendants()的時候返回所有的childFragments。在RequestManagerFragment的onAttach方法以及setParentFragmentHint方法中調用。

(6) unregisterFragmentWithRoot
對應上面的registerFragmentWithRoot方法,在RequestManagerFragment的onDetach,onDestroy或者重新register前將當前的fragment進行remove

很重要的一個相關類:RequestManagerFragment
當Glide.with(context)獲取RequestManager的時候,Glide都會先嚐試獲取當前上下文相關的RequestManagerFragment。

RequestManagerFragment初始化時會創建一個ActivityFragmentLifecycle對象,並在創建自己的Request Manager的時候同時傳入,這樣ActivityFragmentLifecycle便成了它們之間的紐帶。RequestManagerFragment生命週期方法觸發的時候,就可以通過ActivityFragmentLifecycle同時觸發RequestManager相應的方法,執行相應的操作。

Request Manager通過ActivityFragmentLifecycle的addListener方法註冊一些LifecycleListener。當RequestManagerFragment生命週期方法執行的時候,觸發ActivityFragmentLifecycle的相應方法,這些方法會遍歷所有註冊的LifecycleListener並執行相應生命週期方法。

RequestManager註冊的LifecycleListener類型

  • RequestManager自身
    RequestManager自己實現了LifecycleListener。主要的請求管理也是在這裏處理的。

  • RequestManagerConnectivityListener,該listener也實現了LifecycleListener,用於網絡連接時進行相應的請求恢復。 這裏的請求是指那些還未完成的請求,已經完成的請求並不會重新發起。
    另外Target接口也是直接繼承自LifecycleListener,因此RequestManager在觸發相應的生命週期方法的時候也會調用所有Target相應的生命週期方法,這樣開發者可以監聽資源處理的整個過程,在不同階段進行相應的處理。

生命週期的管理主要由RequestTrackerTargetTracker處理。

生命週期事件的傳遞

####4.2.11 RequestManagerFragment
與當前上下文綁定的Fragment,統一管理當前上下文下的所有childFragment的請求。
每一個Context都會擁有一個RequestManagerFragment,在自身的Fragment生命週期方法中觸發listener相應的生命週期方法。
複寫了onLowMemory和onTrimMemory,低內存情況出現的時候,會調用RequestManager的相應方法進行內存清理。

釋放的內存有:

  • bitmapPool:
  • memoryCache:
  • byteArrayPool:

####4.2.12 RequestManagerRetriever
提供一些靜態方法,用語創建或者從Activity/Fragment獲取RequestManager。
get(Activity activity)
get(android.app.Fragment fragment)
get(Activity activity)
get(FragmentActivity activity)
getSupportRequestManagerFragment

####4.2.13 RequestManagerTreeNode
上文提到獲取所有childRequestManagerFragments的RequestManager就是通過該類獲得,就一個方法:getDescendants,作用就是基於給定的Context,獲取所有層級相關的RequestManager。上下文層級由Activity或者Fragment獲得,ApplicationContext的上下文不會提供RequestManager的層級關係,而且Application生命週期過長,所以Glide中對請求的控制只針對於Activity和Fragment。

####4.2.14 LifecycleListener
用於監聽Activity或者Fragment的生命週期方法的接口,基本上請求相關的所有類都實現了該接口

  • void onStart();
  • void onStop();
  • void onDestroy();

####4.2.15 ActivityFragmentLifecycle
用於註冊,同步所有監聽了Activity或者Fragment的生命週期事件的listener的幫助類。

####4.2.16 DataFetcher
每一次通過ModelLoader加載資源的時候都會創建的實例。
loadData :異步方法,如果目標資源沒有在緩存中找到時纔會被調用,cancel方法也是。
cleanup:清理或者回收DataFetcher使用的資源,在loadData提供的數據被decode完成後調用。

主要方法
(1) DataCallback

用於數據加載結果的回調,三種Generator實現了該接口


1
2
3
4

//數據load完成並且可用時回調
void onDataReady(@Nullable T data);
//數據load失敗時回調
void onLoadFailed(Exception e);

(2) getDataClass()
返回fetcher嘗試獲取的數據類型

(3) getDataSource()
獲取數據的來源

(4) DataSource


public enum DataSource {
//數據從本地硬盤獲取,也有可能通過一個已經從遠程獲取到數據的Content Provider
LOCAL,
//數據從遠程獲取
REMOTE,
//數據來自未修改過的硬盤緩存
DATA_DISK_CACHE,
//數據來自已經修改過的硬盤緩存
RESOURCE_DISK_CACHE,
//數據來自內存
MEMORY_CACHE,
}

####4.2.17 DataFetcherGenerator根據註冊的ModelLoaders和model生成一系列的DataFetchers。

FetcherReadyCallbackDecodeJob實現的接口,包含以下方法:reschedule:在Glide自己的線程上再次調用startNext當Generator從DataFetcher完成loadData時回調,含有的方法:onDataFetcherReady:load完成onDataFetcherFailed:load失敗

####4.2.18 Registry管理組件(數據類型+數據處理)的註冊

主要成員變量

  • ModelLoaderRegistry :註冊所有數據加載的loader
  • ResourceDecoderRegistry:註冊所有資源轉換的decoder
  • TranscoderRegistry:註冊所有對decoder之後進行特殊處理的transcoder
  • ResourceEncoderRegistry:註冊所有持久化resource(處理過的資源)數據的encoder
  • EncoderRegistry : 註冊所有的持久化原始數據的encoder

標準的數據處理流程:

Glide在初始化的時候,通過Registry註冊以下所有組件, 每種組件由功能及處理的資源類型組成:

組件 構成
loader model+data+ModelLoaderFactory
decoder dataClass+resourceClass+decoder
transcoder resourceClass+transcodeClass
encoder dataClass+encoder
resourceEncoder resourceClass + encoder
rewind 緩衝區處理

Decoder 數據源 解碼後的資源
BitmapDrawableDecoder Bitmap Drawable
StreamBitmapDecoder InputStream Bitmap
ByteBufferBitmapDecoder ByteBuffer Bitmap
GifFrameResourceDecoder GifDecoder Bitmap
StreamGifDecoder InputStream GifDrawable
ByteBufferGifDecoder ByteBuffer Gif
SvgDecoder InputStream SVG
VideoBitmapDecoder ParcelFileDescriptor Bitmap
FileDecoder File file

Transcoder 數據源 轉換後的資源
BitmapBytesTranscoder Bitmap Bytes
BitmapDrawableTranscoder Bitmap Drawable
GifDrawableBytesTranscoder GifDrawable Bytes
SvgDrawableTranscoder Svg Drawable

decode+transcode的處理流程稱爲decodePath。LoadPath是對decodePath的封裝,持有一個decodePath的List。在通過modelloader.fetchData獲取到data後,會對data進行decode,具體的decode操作就是通過loadPath來完成。resourceClass就是asBitmap,asDrawable方法的參數。

ModelLoaderRegistry持有多個ModelLoader,model和數據類型按照優先級進行處理

loader註冊示例:


1
2
3

registry
.append(Integer.class, InputStream.class, new ResourceLoader.StreamFactory())
.append(GifDecoder.class, GifDecoder.class, new UnitModelLoader.Factory<GifDecoder>())

主要函數
(1) register,append,prepend

註冊各種功能的組件

(2) getRegisteredResourceClasses(Class modelClass, Class resourceClass, Class transcodeClass)
獲取Glide初始化時註冊的所有resourceClass

(3) getModelLoaders(Model model)

(4) hasLoadPath(Class<?> dataClass)
判斷註冊的組件是否可以處理給定的dataClass

  • 直接調用getLoadPath(dataClass, resourceClass, transcodeClass)
  • 該方法先從loadPathCache緩存中嘗試獲取LoadPath,如果沒有,則先根據dataClass, resourceClass, transcodeClass獲取所有的decodePaths,如果decodePaths不爲空,則創建一個LoadPath<>(dataClass, resourceClass, transcodeClass, decodePaths,exceptionListPool)並緩存起來。

(5) getDecodePaths
根據dataClass, resourceClass, transcodeClass從註冊的組件中找到所有可以處理的組合decodePath。就是將滿足條件的不同處理階段(modelloader,decoder,transcoder)的組件組合在一起。滿足處理條件的有可能是多個組合。因爲decodePath的功能是進行decode和transcode,所以getDecodePath的目的就是要找到符合條件的decoder和transcoder然後創建DecodePath。

####4.2.19 ModelLoader

ModelLoader是一個工廠接口。將任意複雜的model轉換爲準確具體的可以被DataFetcher獲取的數據類型。
每一個model內部實現了一個ModelLoaderFactory,內部實現就是將model轉換爲Data

重要成員
LoadData<Data>
Key sourceKey,用於表明load數據的來源。
List alternateKeys:指向相應的變更數據
DataFetcher fetcher:用於獲取不在緩存中的數據

重要方法

(1) buildLoadData
返回一個LoadData

(2) handles(Model model)
判斷給定的model是否可以被當前modelLoader處理

####4.2.20 ModelLoaderFactory
根據給定的類型,創建不同的ModelLoader,因爲它會被靜態持有,所以不應該維持非應用生命週期的context或者對象。

####4.2.21 DataFetcherGenerator
通過註冊的DataLoader生成一系列的DataFetcher
DataCacheGenerator:根據未修改的緩存數據生成DataFetcher
ResourceCacheGenerator:根據已處理的緩存數據生成DataFetcher
SourceGenerator:根據原始的數據和給定的model通過ModelLoader生成的DataFetcher

####4.2.22 DecodeHelper
getPriority
getDiskCache
getLoadPath
getModelLoaders
getWidth
getHeight

如何監測當前context的生命週期?

爲當前的上下文Activity或者Fragment綁定一個TAG爲”com.bumptech.glide.manager”的RequestManagerFragment,然後把該fragment作爲rootRequestManagerFragment,並加入到當前上下文的FragmentTransaction事務中,從而與當前上下文Activity或者Fragment的生命週期保持一致。

關鍵就是RequestManagerFragment,用於綁定當前上下文以及同步生命週期。比如當前的context爲activity,那麼activity對應的RequestManagerFragment就與宿主activity的生命週期綁定了。同樣Fragment對應的RequestManagerFragment的生命週期也與宿主Fragment保持一致。

####五 請求管理的實現
pauseRequestsresumeRequests
在RequestManagerFragment對應Request Manager的生命週期方法中觸發,

#####5.1 如何控制當前上下文的所有ChildFragment的請求?
情景:
假設當前上下文是Activity(Fragment類似)創建了多個Fragment,每個Fragment通過Glide.with(fragment.this)方式加載圖片

  • 首先Glide會爲Activity以及每一個Fragment創建一個RequestManagerFragment(原因看下面)並提交到當前上下文的事務中。
    以上保證了每個Fragment以及對應的RequestManagerFragment生命週期是與Activity的生命週期綁定的。
  • 在RequestManagerFragment的onAttach方法中通過Glide.with(activity.this)先獲得Activity(宿主)的RequestManagerFragment(rootRequestManagerFragment),並將每個Fragment相應的RequestManagerFragment添加到childRequestManagerFragments集合中。
  • Activity通過自己的RequestManager的childRequestManagerFragments獲取所有childFragment的RequestManager,然後對請求進行pause,resume。

同理,如果當前context是Fragment,Fragment對應的RequestManagerFragment可以獲取它自己所有的Child Fragment的RequestManagerFragment。

#####5.2 如何管理沒有ChildFragment的請求?
很簡單,只會存在當前context自己的RequestManagerFragment,那麼伴隨當前上下文的生命週期觸發,會調用RequestManagerFragment的RequestManager相應的lefecycle方法實現請求的控制,資源回收。

#####5.3 爲何每一個上下文會創建自己的RequestManagerFragment ?
因爲RequestManagerRetriever.getSupportRequestManagerFragment(fm)是通過FragmentManager來獲取的

  • 如果傳入到Glide.with(…)的context是activity
    fm = activity.getSupportFragmentManager();
  • 如果傳入到Glide.with(…)的context是Fragment
    fm = fragment.getChildFragmentManager();

因爲上下文不同導致得到的fm不同,從而RequestManagerRetriever.getSupportRequestManagerFragment(fm)方法返回的RequestManagerFrament不同。而且如果一個activity下面有多個Fragment,並以Glide.with(fragment.this)的方式加載圖片。那麼每個Fragment都會爲自己創建一個fm相關的RequestManagerFragment。

關鍵在於每一個上下文擁有一個自己的RequestManagerFragment。而傳入的context不同,會返回不同的RequestManagerFragment,頂層上下文會保存所有的childRequestManagerFragments。

###六. 雜談
Glide優點在於其生命週期的管理,資源類型的支持多。但相對於簡潔的UniversalImageLoader和Picasso,無論從設計上還是細節實現上,都複雜的多,從代碼的實現上可以看出,正式因爲Glide的生命週期管理,內存友好,資源類型支持多這些優點相關。一些設計概念很少碰到,比如decodePath,loadpath。整個數據處理流程的拆分三個部分,每個部分所支持的數據以及處理方式全部通過組件註冊的方式來支持,很多方法或者構造函數會接收10多個參數,看着着實眼花繚亂。這裏的分析把大體的功能模塊分析了,比如請求的統一管理,生命週期的同步,具體的實現細節還需要一部分的工作量。對於開源項目的初學者來說,Glide並不是一個好的項目,門檻太高。也因爲如此,所以Glide的使用並沒有其它幾種圖片庫的使用那麼廣泛,相關文檔很欠缺,本篇分析希望成爲一個很好的參考,也希望大家提出自己的建議和意見,繼續優化,讓更多開發者能更快了解,使用這個強大的庫。

###參考文檔
開源選型之 Android 三大圖片緩存原理、特性對比
get-to-know-glide-recommended-by-google
picasso-vs-imageloader-vs-fresco-vs-glide
https://plus.google.com/+HugoVisser/posts/Rra8mrU1pCx
http://blog.csdn.net/fancylovejava/article/details/44747759

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章