0.基礎知識
Glide中有一部分單詞,我不知道用什麼中文可以確切的表達出含義,用英文單詞可能在行文中更加合適,還有一些詞在Glide中有特別的含義,我理解的可能也不深入,這裡先記錄一下。
(1)View: 一般情況下,指Android中的View及其子類控制項(包括自訂的),尤其指ImageView。這些控制項可在上面繪製Drawable
(2)Target: Glide中重要的概念,目標。它即可以指封裝了一個View的Target(ViewTarget),也可以不包含View(SimpleTarget)。
(3)Drawable: 指Android中的Drawable類或者它的子類,如BitmapDrawable等。或者Glide中基礎Drawable實現的自訂Drawable(如GifDrawable等)
(4)Request - 載入請求,可以是網路請求或者其他任何下載圖片的請求,也是Glide中的一個類。
(5)Model:資料來源的提供者,如Url,檔案路徑等,可以從model中擷取InputStream。
(6)Signature:簽名,可以唯一地標識一個對象。
(7)recycle():Glide中Resource類有此方法,表示該資源不被引用,可以放入池中(此時並沒有釋放空間)。Android中Bitmap也有此方法,表示釋放Bitmap佔用的記憶體。
1.主要特點
(1)支援Memory和Disk圖片緩衝。
(2)支援gif和webp格式圖片。
(3)根據Activity/Fragment生命週期自動管理請求。
(4)使用Bitmap Pool可以使Bitmap複用。
(5)對於回收的Bitmap會主動調用recycle,減小系統回收壓力。
2. 總體設計
基本概念
RequestManager:要求管理,每一個Activity都會建立一個RequestManager,根據對應Activity的生命週期管理該Activity上所以的圖片請求。
Engine:載入圖片的引擎,根據Request建立EngineJob和DecodeJob。
EngineJob:圖片載入。
DecodeJob:圖片處理。
流程圖
這裡是大概的總體流程圖, 具體的細節中流程下面繼續分析。
3. 核心類介紹
3.1 Gilde
用於儲存整個架構中的配置。
重要方法:
public static RequestManager with(FragmentActivity activity) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(activity);}
用於建立RequestManager,這裡是Glide通過Activity/Fragment生命週期管理Request原理所在,這個類很關鍵、很關鍵、很關鍵,重要的事情我只說三遍。
主要原理是建立一個自訂Fragment,然後通過自訂Fragment生命週期操作RequestManager,從而達到管理Request。
3.2 RequestManagerRetriever
RequestManager supportFragmentGet(Context context, FragmentManager fm) { SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode()); current.setRequestManager(requestManager); } return requestManager;}
這裡判斷是否只當前RequestManagerFragment是否存在RequestManager,保證一個Activity對應一個RequestManager, 這樣有利於管理一個Activity上所有的Request。建立RequestManager的時候會將RequestManagerFragment中的回調介面賦值給RequestManager,達到RequestManager監聽RequestManagerFragment的生命週期。
3.3 RequestManager
成員變數:
(1)Lifecycle lifecycle,用於監聽RequestManagerFragment生命週期。
(2)RequestTracker requestTracker, 用於儲存當前RequestManager所有的請求和帶處理的請求。
重要方法:
@Override//開始暫停請求public void onStart() { resumeRequests();}//停止所有的請求@Overridepublic void onStop() { pauseRequests();} //關閉所以的請求@Overridepublic void onDestroy() { requestTracker.clearRequests();} //建立RequestBuildpublic DrawableTypeRequest<String> load(String string) { return (DrawableTypeRequest<String>) fromString().load(string);} public <Y extends Target<TranscodeType>> Y into(Y target) { ... Request previous = target.getRequest(); //停止當前target中的Request。 if (previous != null) { previous.clear(); //這個地方很關鍵,見Request解析 requestTracker.removeRequest(previous); previous.recycle(); } ... return target;}
3.4 DrawableRequestBuilder
用於建立Request。 這裡麵包括很多方法,主要是配置載入圖片的url、大小、動畫、ImageView對象、自訂圖片處理介面等。
3.5 Request
主要是操作請求,方法都很簡單。
@Overridepublic void clear() { ... if (resource != null) { //這裡會釋放資源 releaseResource(resource); } ...}
這裡的基本原理是當有Target使用Resource(Resource見下文)時,Resource中的引用記數值會加一,當釋放資源Resource中的引用記數值減一。當沒有Target使用的時候就會釋放資源,放進Lrucache中。
3.6 EngineResource
實現Resource介面,使用裝飾模式,裡麵包含實際的Resource對象
void release() { if (--acquired == 0) { listener.onResourceReleased(key, this); }} void acquire() { ++acquired;} @Overridepublic void recycle() { isRecycled = true; resource.recycle();}
acquire和release兩個方法是對資源引用計數;recycle釋放資源,一般在Lrucache飽和時會觸發。
3.7 Engine(重要)
請求引擎,主要做請求的開始的初始化。
3.7.1 load方法
這個方法很長,將分為幾步分析
(1)擷取MemoryCache中緩衝 首先建立當前Request的緩衝key,通過key值從MemoryCache中擷取緩衝,判斷緩衝是否存在。
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) { .... EngineResource<?> cached = getEngineResourceFromCache(key); if (cached != null) { cached.acquire(); activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue())); } return cached;} @SuppressWarnings("unchecked")private EngineResource<?> getEngineResourceFromCache(Key key) { Resource<?> cached = cache.remove(key); final EngineResource result; ... return result;}
(重點)從緩衝中擷取的時候使用的cache.remove(key),然後將值儲存在activeResources中,然後將Resource的引用計數加一。
優點:
> 正使用的Resource將會在activeResources中,不會出現在cache中,當MemoryCache中緩衝飽和的時候或者系統記憶體不足的時候,清理Bitmap可以直接調用recycle,不用考慮Bitmap正在使用導致異常,加快系統的回收。
(2)擷取activeResources中緩衝
activeResources通過弱引用儲存recouse ,也是通過key擷取緩衝,
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable)
(3)判斷當前的請求任務是否已經存在
EngineJob current = jobs.get(key);if (current != null) { current.addCallback(cb); return new LoadStatus(cb, current);}
如果工作要求已經存在,直接將回調事件傳遞給已經存在的EngineJob,用於請求成功後觸發回調。
(4)執行請求任務
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation, transcoder, diskCacheProvider, diskCacheStrategy, priority);EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);jobs.put(key, engineJob);engineJob.addCallback(cb);engineJob.start(runnable);
3.8 EngineRunnable
請求執行Runnable,主要功能請求資源、處理資源、緩衝資源。
private Resource<?> decodeFromCache() throws Exception { Resource<?> result = null; try { result = decodeJob.decodeResultFromCache(); } catch (Exception e) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Exception decoding result from cache: " + e); } } if (result == null) { result = decodeJob.decodeSourceFromCache(); } return result;} private Resource<?> decodeFromSource() throws Exception { return decodeJob.decodeFromSource();}
載入DiskCache和網路資源。載入DiskCache包括兩個,因為Glide預設是儲存處理後的資源(壓縮和裁剪後),緩衝方式可以自訂配置。如果用戶端規範設計,ImageView大小大部分相同可以節省圖片載入時間和Disk資源。
3.9 DecodeJob
public Resource<Z> decodeResultFromCache() throws Exception
從緩衝中擷取處理後的資源。上面有關Key的內容,Key是一個對象,可以擷取key和orginKey。decodeResultFromCache就是通過key擷取緩衝,decodeSourceFromCache()就是通過orginKey擷取緩衝。
private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded)
處理和封裝資源;緩衝資源。
儲存原資源
private Resource<T> cacheAndDecodeSourceData(A data) throws IOException
儲存處理後的資源
private void writeTransformedToCache(Resource<T> transformed)
3.10 Transformation
Resource<T> transform(Resource<T> resource, int outWidth, int outHeight);
處理資源,這裡面出現BitmapPool類,達到Bitmap複用。
3.11 ResourceDecoder
用於將檔案、IO流轉化為Resource
3.12 BitmapPool
用於存放從LruCache中remove的Bitmap, 用於後面建立Bitmap時候的重複利用。
4.雜談
Glide的架構擴充性高,但是難以理解,各種介面、泛型,需要一定的學習才能熟練運用。
Glide的優點:
(1)支援對處理後的資源Disk緩衝。
(2)通過BitmapPool對Bitmap複用。
(3)使用activityResources緩衝正在使用的resource,對於BitmapPool飽和移除的Bitmap直接調用recycle加速記憶體回收。