Fresco 一共有三級(jí)緩存機(jī)制门烂,其中前兩級(jí)內(nèi)存緩存都存儲(chǔ)在java heap中,本地緩存存儲(chǔ)在本地文件目錄中逛球。
CacheKey
Fresco中專門用于緩存鍵的接口千元,在CacheKeyFactory中定義了獲取Cachekey的工廠方法。有這兩種類實(shí)現(xiàn)了CacheKey:
BitmapMemoryCacheKey
用于已解碼的內(nèi)存緩存鍵颤绕,會(huì)對(duì)Uri字符串幸海、縮放尺寸、解碼參數(shù)屋厘、PostProcessor等關(guān)鍵參數(shù)進(jìn)行hashCode作為唯一標(biāo)識(shí)涕烧;通過CacheKeyFactory中的getBitmapCacheKey工廠方法獲取,具體的實(shí)現(xiàn)請(qǐng)參考實(shí)現(xiàn)實(shí)現(xiàn)類類DefaultCacheKeyFactory中的getBitmapCacheKey工廠方法汗洒。
SimpleCacheKey
普通的緩存鍵實(shí)現(xiàn)议纯,使用傳入字符串的hashCode作為唯一標(biāo)識(shí),所以需要保證相同鍵傳入字符串相同溢谤。
通過CacheKeyFactory的getEncodedCacheKey工廠方法實(shí)現(xiàn)瞻凤,具體的實(shí)現(xiàn)請(qǐng)參考實(shí)現(xiàn)實(shí)現(xiàn)類類DefaultCacheKeyFactory中的getEncodedCacheKey工廠方法。
內(nèi)存緩存
已解碼的內(nèi)存緩存(BitmapMemoryCache)與未解碼的內(nèi)存緩存(EncodedMemoryCache)區(qū)別就是已解碼內(nèi)存緩存的數(shù)據(jù)是CloseableReference<CloseableBitmap>而未解碼內(nèi)存緩存的數(shù)據(jù)是CloseableReference世杀。即他們的實(shí)現(xiàn)方式一樣阀参,區(qū)別僅僅在于資源的測(cè)量與釋放方式不同。它們使用ValueDescriptor來描述不同資源的數(shù)據(jù)大小瞻坝,使用不同的ResourceReleaser來釋放資源蛛壳。
BitmapMemoryCache(已解碼的內(nèi)存緩存)
BitmapMemoryCacheFactory提供工廠方法獲取存儲(chǔ)緩存的數(shù)據(jù)結(jié)構(gòu),即下面的mMemoryCache的原始對(duì)象:
通過BitmapMemoryCacheProducer類中的wrapConsumer方法生成一個(gè)Consumer對(duì)象所刀,在onNewResultImpl中把解碼處理的圖片放到內(nèi)存緩存中衙荐,返回一個(gè)CloseableReference<CloseableImage>對(duì)象:
EncodedMemoryCache(未解碼的內(nèi)存緩存)
EncodedCountingMemoryCacheFactory提供工廠方法獲取存儲(chǔ)緩存的數(shù)據(jù)結(jié)構(gòu),即下面的mMemoryCache的原始對(duì)象:
通過EncodedCountingMemoryCacheFactory類中的靜態(tài)內(nèi)部類EncodedMemoryCacheConsumer浮创,在onNewResultImpl中把解碼處理的圖片放到內(nèi)存緩存中忧吟,返回一個(gè)CloseableReference對(duì)象:
Fresco中定義的LRU緩存載體-CountingLruMap
內(nèi)存緩存中使用了LRU(Least Recent Used)來提高緩存功能,說明一下具體實(shí)現(xiàn)邏輯:
在CountingLruMap中使用了LinkedHashMap作為數(shù)據(jù)存儲(chǔ)載體斩披,這個(gè)HashMap很特別溜族,它內(nèi)部有一個(gè)雙向鏈表讹俊,在做查找操作的時(shí)候,從最先插入的單位開始查詢煌抒。這就提供了一種好處:**它能夠很快地刪除掉最早插入的單位仍劈!**所以它非常適合LRU緩存來使用。
但是由于在LinkedHashMap中重復(fù)插入相同單位并不會(huì)影響鏈表順序摧玫,所以要用CountingLruMap將它包裝凹联,我們來看看它put對(duì)象時(shí)的邏輯:
**它會(huì)先將要插入的對(duì)象remove掉慧耍,然后重新插入該對(duì)象!**由此來保證最新加入的對(duì)象處于正確地插入順序中畏梆。同時(shí)在mSizeBytes中更新現(xiàn)在緩存池中所有對(duì)象的字節(jié)數(shù)闸婴。
在CountingHruMap中還有以下幾個(gè)重要函數(shù):
get(Key)查找對(duì)象坏挠,如有則返回;
remove(Key)刪除對(duì)象并返回它邪乍;
getFirstkey()獲取最早插入的對(duì)象降狠;
getCount()獲取已經(jīng)緩存的對(duì)象數(shù);
getSizeInBytes()獲取緩存池中已經(jīng)使用的大小庇楞。
具體緩存緩存實(shí)現(xiàn)-CountingMemoryCache
Fresco中實(shí)現(xiàn)具體內(nèi)存緩存的類是CountingMemoryCache榜配,它內(nèi)部維持著幾個(gè)重要參數(shù):
ExclusiveEntries存儲(chǔ)著未被使用的對(duì)象的CountingLruMap;
CachedEntries存儲(chǔ)著所有對(duì)象的CountingLruMap吕晌;
MemoryCacheParams存儲(chǔ)著最大緩存對(duì)象數(shù)量蛋褥、緩存池大小等參數(shù)、
PARAMS_INTERCHECK_INTERVAL_MS檢查緩存參數(shù)變化的事件間隔:5分鐘睛驳;
它使用一個(gè)內(nèi)部類Entry來封裝緩存對(duì)象烙心,除了記錄緩存鍵、緩存對(duì)象之外乏沸,它還記錄著該對(duì)象的引用數(shù)量(clientCount)及是否被緩存追蹤(isOrphan)淫茵。注意:每個(gè)緩存對(duì)象只有滿足clientCount為0并且isOrphan為true時(shí)才可以被釋放,可從referenceToClose函數(shù)中看出此邏輯蹬跃。
緩存對(duì)象邏輯:
Instrument包裝
Fresco使用InstrumentedMemoryCache包裝了CountingMemoryCache匙瘪,主要增加的功能就是提供了MemoryCacheTracker,會(huì)在緩存命中或未命中時(shí)提供回調(diào)函數(shù)蝶缀,供使用者實(shí)現(xiàn)自定義功能丹喻。
自定義MemoryCacheParams參數(shù):
可以通過ImagePipelineConfig的以下兩個(gè)函數(shù)來實(shí)現(xiàn)內(nèi)存緩存參數(shù)部分自定義:setBitmapMemoryCacheParamsSupplier(Supplier bitmapMemoryCacheParamsSupplier)
setEncodedMemoryCacheParamsSupplier(Supplier encodedMemoryCacheParamsSupplier)
這兩個(gè)函數(shù)都需要提供MemoryCacheParams的Supplier,使用者可以自定義ImagePipelineConfig之后在初始化中應(yīng)用它扼劈。