本文源碼解析基于Glide 4.6.1
系列文章
Android 【手撕Glide】--Glide緩存機(jī)制
Android 【手撕Glide】--Glide緩存機(jī)制(面試)
Android 【手撕Glide】--Glide是如何關(guān)聯(lián)生命周期的饭弓?
引入緩存的目的
- 1油猫、減少流量消耗装盯,加快響應(yīng)速度;
- 2士鸥、Bitmap 的創(chuàng)建/銷毀比較耗內(nèi)存,可能會(huì)導(dǎo)致頻繁GC;使用緩存可以更加高效地加載 Bitmap蛾洛,減少卡頓。
Glide緩存流程
Glide緩存分為內(nèi)存緩存和磁盤(pán)緩存雁芙,其中內(nèi)存緩存是由弱引用+LruCache組成轧膘。
取的順序是:弱引用、LruCache兔甘、磁盤(pán)
存的順序是:磁盤(pán)谎碍、弱引用、LruCache
這張親手制作的圖片洞焙,方便大家更直觀的理解緩存機(jī)制的整體流程蟆淀,結(jié)合文末總結(jié)效果更佳。喜歡的記得點(diǎn)贊澡匪!
注意:關(guān)于緩存的存取的入口在
Engine
這個(gè)類中
內(nèi)存緩存原理
概述
1熔任、弱引用是由這樣一個(gè)HashMap維護(hù),key是緩存的key唁情,這個(gè)key由圖片url疑苔、width、height等10來(lái)個(gè)參數(shù)組成甸鸟;value是圖片資源對(duì)象的弱引用形式惦费。
Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
2、LruCache是由一個(gè)LinkedHashMap維護(hù)抢韭,根據(jù)Lru算法來(lái)管理圖片薪贫。大致的原理是利用linkHashMap鏈表的特性,把最近使用過(guò)的文件插入到鏈表尾部篮绰,沒(méi)使用的圖片在頭部后雷;然后當(dāng)圖片大小到達(dá)預(yù)先設(shè)置的一個(gè)閾值的時(shí)候 ,按算法刪除鏈表頭部的數(shù)據(jù)。由于篇幅有限臀突,這里不講解LruCache和DiskLruCache的底層原理勉抓,這里推薦一篇 圖解LinkedHashMap原理
這是Glide自定義的LruCache
#LruCache
Map<T, Y> cache = new LinkedHashMap<>(100, 0.75f, true);
存取原理
取數(shù)據(jù)
在內(nèi)存緩存中有一個(gè)概念叫圖片引用計(jì)數(shù)器 ,具體來(lái)說(shuō)是在EngineResource
中定義一個(gè)acquired
變量用來(lái)記錄圖片被引用的次數(shù)候学,調(diào)用acquire()
方法會(huì)讓變量加1藕筋,調(diào)用release()
方法會(huì)讓變量減1。
獲取圖片資源是先從弱引用取緩存梳码,拿到的話隐圾,引用計(jì)數(shù)+1;沒(méi)有的話從LruCache中拿緩存掰茶,拿到的話暇藏,引用計(jì)數(shù)也是+1,同時(shí)把圖片從LruCache緩存轉(zhuǎn)移到弱應(yīng)用緩存池中濒蒋;再?zèng)]有的話就通過(guò)EngineJob
開(kāi)啟線程池去加載圖片盐碱,拿到的話,引用計(jì)數(shù)也是+1沪伙,會(huì)把圖片放到弱引用瓮顽。
存數(shù)據(jù)
很明顯,這是加載圖片之后的事情围橡。通過(guò)EngineJob
開(kāi)啟線程池去加載圖片暖混,取到數(shù)據(jù)之后,會(huì)回調(diào)到主線程翁授,把圖片存到弱引用拣播。當(dāng)圖片不再使用的時(shí)候,比如說(shuō)暫停請(qǐng)求或者加載完畢或者清除資源時(shí)黔漂,就會(huì)將其從弱引用中轉(zhuǎn)移到LruCache
緩存池中诫尽。總結(jié)一下,就是正在使用中的圖片使用弱引用
來(lái)進(jìn)行緩存炬守,暫時(shí)不用的圖片使用LruCache
來(lái)進(jìn)行緩存的功能;同一張圖片只會(huì)出現(xiàn)在弱引用
和LruCache
中的一個(gè)。
為什么要引入弱引用
剂跟?
- 避免正在使用的圖片被回收
- 分壓策略减途,減少Lrucache 中
trimToSize
的概率。如果正在remove的是張大圖曹洽,lrucache正好處在臨界點(diǎn)鳍置,此時(shí)remove操作,將延緩Lrucache的trimToSize
操作送淆; - 提高效率:弱引用用的是
HashMap
税产,Lrucache用的是LinkedHashMap
,從訪問(wèn)效率而言,肯定是HashMap
更高。
磁盤(pán)緩存原理(DiskLruCache)
Glide磁盤(pán)緩存策略(4.x)
-
DiskCacheStrategy.DATA
: 只緩存原始圖片辟拷; -
DiskCacheStrategy.RESOURCE
:只緩存轉(zhuǎn)換過(guò)后的圖片撞羽; -
DiskCacheStrategy.ALL
:既緩存原始圖片,也緩存轉(zhuǎn)換過(guò)后的圖片衫冻;對(duì)于遠(yuǎn)程圖片诀紊,緩存 DATA和 RESOURCE;對(duì)于本地圖片隅俘,只緩存 RESOURCE邻奠; -
DiskCacheStrategy.NONE
:不緩存任何內(nèi)容; -
DiskCacheStrategy.AUTOMATIC
:默認(rèn)策略为居,嘗試對(duì)本地和遠(yuǎn)程圖片使用最佳的策略碌宴。當(dāng)下載網(wǎng)絡(luò)圖片時(shí),使用DATA
(原因很簡(jiǎn)單蒙畴,對(duì)本地圖片的處理可比網(wǎng)絡(luò)要容易得多)唧喉;對(duì)于本地圖片,使用RESOURCE
忍抽。
如果在內(nèi)存緩存中沒(méi)獲取到數(shù)據(jù)會(huì)通過(guò)EngineJob
開(kāi)啟線程池去加載圖片,這里有2個(gè)關(guān)鍵類:DecodeJob
和EngineJob
八孝。EngineJob
內(nèi)部維護(hù)了線程池,用來(lái)管理資源加載鸠项,當(dāng)資源加載完畢的時(shí)候通知回調(diào)干跛; DecodeJob
是線程池中的一個(gè)任務(wù)。
磁盤(pán)緩存是通過(guò)DiskLruCache
來(lái)管理的,根據(jù)緩存策略祟绊,會(huì)有2種類型的圖片楼入,DATA
(原始圖片)和 RESOURCE
(轉(zhuǎn)換后的圖片)。磁盤(pán)緩存依次通過(guò)ResourcesCacheGenerator
牧抽、SourceGenerator
嘉熊、DataCacheGenerator
來(lái)獲取緩存數(shù)據(jù)。ResourcesCacheGenerator
獲取的是轉(zhuǎn)換過(guò)的緩存數(shù)據(jù)扬舒;SourceGenerator
獲取的是未經(jīng)轉(zhuǎn)換的原始的緩存數(shù)據(jù)阐肤;DataCacheGenerator
是通過(guò)網(wǎng)絡(luò)獲取圖片數(shù)據(jù)再按照按照緩存策略的不同去緩存不同的圖片到磁盤(pán)上。
總結(jié)(干貨)
Glide緩存分為弱引用+ LruCache+ DiskLruCache
讲坎,其中讀取數(shù)據(jù)的順序是:弱引用 > LruCache > DiskLruCache>網(wǎng)絡(luò)孕惜;寫(xiě)入緩存的順序是:網(wǎng)絡(luò) --> DiskLruCache-->弱引用 --> LruCache
內(nèi)存緩存分為弱引用的和 LruCache ,其中正在使用的圖片使用弱引用緩存晨炕,暫時(shí)不使用的圖片用 LruCache緩存衫画,這一點(diǎn)是通過(guò) 圖片引用計(jì)數(shù)器(acquired變量)來(lái)實(shí)現(xiàn)的,詳情可以看內(nèi)存緩存的小結(jié)瓮栗。
磁盤(pán)緩存就是通過(guò)DiskLruCache實(shí)現(xiàn)的削罩,根據(jù)緩存策略的不同會(huì)獲取到不同類型的緩存圖片瞄勾。它的邏輯是:先從轉(zhuǎn)換后的緩存中取弥激;沒(méi)有的話再?gòu)脑嫉模](méi)有轉(zhuǎn)換過(guò)的)緩存中拿數(shù)據(jù)进陡;再?zèng)]有的話就從網(wǎng)絡(luò)加載圖片數(shù)據(jù),獲取到數(shù)據(jù)之后秆撮,再依次緩存到磁盤(pán)和弱引用四濒。
參考:
面試官:簡(jiǎn)歷上最好不要寫(xiě)Glide,不是問(wèn)源碼那么簡(jiǎn)單
原來(lái)面試的時(shí)候?qū)懢℅lide职辨,這樣問(wèn)我這樣答