Android 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空閑的時候會觸發該回調

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 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, 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

1
2
3
4
5
6
7
8
9
10
11
12
public enum DataSource {
//數據從本地硬盤獲取,也有可能通過一個已經從遠程獲取到數據的Content Provider
LOCAL,
//數據從遠程獲取
REMOTE,
//數據來自未修改過的硬盤緩存
DATA_DISK_CACHE,
//數據來自已經修改過的硬盤緩存
RESOURCE_DISK_CACHE,
//數據來自內存
MEMORY_CACHE,
}

4.2.17 DataFetcherGenerator

根據注冊的ModelLoaders和model生成一系列的DataFetchers。

FetcherReadyCallback
DecodeJob實現的接口,包含以下方法:
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的使用並沒有其它幾種圖片庫的使用那么廣泛,相關文檔很欠缺,本篇分析希望成為一個很好的參考,也希望大家提出自己的建議和意見,繼續優化,讓更多開發者能更快了解,使用這個強大的庫。


免責聲明!

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



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