Android Glide(一)緩存機制

什么是Glide

Glide是一款由Bump Technologies開發(fā)的圖片加載框架,使得我們可以在Android平臺上以極度簡單的方式加載和展示圖片。這也是Google官方推薦的圖片加載框架。

如何使用Glide

Glide.with(this).load(url).into(imageView);
一切就是這么簡單。
僅僅就這一行代碼,已經(jīng)可以做非常非常多的事情了,包括加載網(wǎng)絡(luò)上的圖片、加載手機本地的圖片、加載應(yīng)用資源中的圖片等等。

我們簡單地分析一下這行代碼

.with()

用于創(chuàng)建一個加載圖片的實例。
with()方法可以接收Context、Activity或者Fragment類型的參數(shù)。

.load()

這個方法用于指定待加載的圖片資源。
Glide支持加載各種各樣的圖片資源,包括網(wǎng)絡(luò)圖片、本地圖片、應(yīng)用資源、二進制流、Uri對象等等。因此load()方法也有很多個方法重載。

.into()

這個方法就很簡單了,我們希望讓圖片顯示在哪個ImageView上,把這個ImageView的實例傳進去就可以了。
除此之外,
Glide.with(this)
.load(url)
.placeholder(R.drawable.loading) //加載占位圖。
.error(R.drawable.error) //加載失敗時的占位圖
.diskCacheStrategy(DiskCacheStrategy.NONE) //這里是可以選擇Glide的緩存策略
.override(100, 100) //指定圖片大小
.asGif() //指定圖片格式
.into(imageView);

那么回顧一下Glide最基本的使用方式,其實就是關(guān)鍵的三步走:先with(),再load(),最后into()。熟記這三步,你就已經(jīng)入門Glide了。
沒錯,就是這么簡單。正所謂大道至簡。當(dāng)然我并不是要教大家如何使用Glide,畢竟需要用的人已經(jīng)會了,不需要用的人也沒必要學(xué)會。我只是想給你們看看它有多好用。
這個框架用起來實在是太舒服了,簡潔明了,一秒種就能入門。
但是,哪有什么歲月靜好,不過是有人替你負(fù)重前行。
我們今天之所以能夠這么簡單的加載圖片,當(dāng)然是有人在背后做了成噸的工作。

今天只分析Glide緩存機制

Glide的緩存機制

首先,為什么要緩存?

  • 1、減少流量消耗,加快響應(yīng)速度;
  • 2、Bitmap 的創(chuàng)建/銷毀比較耗內(nèi)存,可能會導(dǎo)致頻繁GC;使用緩存可以更加高效地加載 Bitmap,減少卡頓。

Glide的緩存結(jié)構(gòu)

首先明確一點,Glide是三級緩存。
緩存是內(nèi)存--->磁盤--->網(wǎng)絡(luò)這樣的方式去獲取圖片資源的,但這就是3級緩存嗎?明顯不是,這個只是2級緩存;Glide也是按照這種策略來獲取圖片的,但是還略有不同,Glide將它的緩存分為2個大的部分,一個是內(nèi)存緩存,一個是硬盤緩存。其中內(nèi)存緩存又分為2種,弱引用(正在使用的資源)和Lrucache;磁盤緩存就是DiskLrucache,DiskLrucache算法和Lrucache差不多的,所以現(xiàn)在看起來Glide3級緩存的話應(yīng)該是WeakReference + Lrucache + DiskLrucache。
內(nèi)存緩存的主要作用是防止應(yīng)用重復(fù)將圖片數(shù)據(jù)讀取到內(nèi)存當(dāng)中;而硬盤緩存的主要作用是防止應(yīng)用重復(fù)從網(wǎng)絡(luò)或其他地方下載和讀取數(shù)據(jù)。

Glide的緩存Key

緩存是為了解決重復(fù)加載問題,那必然要有一個key來區(qū)分不同的圖片資源。決定緩存Key的參數(shù)有很多種,其中包括圖片URL、寬、高。
這里可以得出一個結(jié)論,幾乎任意配置的改變都會導(dǎo)致同一張圖片生成多個緩存key。
舉個例子:同一張圖片加載到2個不同大小的ImageView會生成2個緩存圖片。

Glide的緩存的讀寫

前面提到過內(nèi)存緩存是通過弱引用+LruCache的方式實現(xiàn)的。

  • 弱引用是由一個HashMap維護,key是上述的緩存key;value是圖片資源對象的弱引用形式。
  • LruCache是由一個LinkedHashMap維護,根據(jù)Lru算法來管理圖片。
    大致的原理是利用LinkedHashMap鏈表的特性,把最近使用過的文件插入到列表頭部,沒使用的圖片放在尾部;然后當(dāng)圖片大小到達(dá)預(yù)先設(shè)置的一個閥值的時候 ,按算法刪除列表尾部的部分?jǐn)?shù)據(jù)。
  • DiskLruCache也是類似原理。由于篇幅有限,這里不講解LruCache和DiskLruCache的底層原理,這里推薦一篇文章 http://www.itdecent.cn/p/8f4f58b4b8ab

內(nèi)存緩存原理

  • 讀數(shù)據(jù)
    靈魂畫手出馬


    未命名.png

在內(nèi)存緩存中有一個概念叫圖片引用資源計數(shù)器 ,抽象來說,就是定義一個acquired變量用來記錄圖片被引用的次數(shù),調(diào)用acquire()方法會讓變量加1,調(diào)用release()方法會讓變量減1。
獲取圖片資源是先從弱引用取緩存,拿到的話,引用計數(shù)+1;
沒有的話從LruCache中拿緩存,拿到的話,從LruCache中刪除這張圖片,引用計數(shù)也是+1,同時把圖片從LruCache緩存轉(zhuǎn)移到弱應(yīng)用緩存池中;(這里如果再次讀取就可以直接從弱引用中獲取了)
再沒有的話就通過EngineJob開啟線程池去加載圖片,拿到的話,引用計數(shù)也是+1,會把圖片放到弱引用。(但這是后話了)

  • 寫數(shù)據(jù)
    很明顯,這是加載圖片之后的事情。通過EngineJob開啟線程池去加載圖片,取到數(shù)據(jù)之后,會回調(diào)到主線程,把圖片存到弱引用。
    當(dāng)圖片不再使用的時候,比如說暫停請求或者加載完畢或者清除資源時,就會將其從弱引用中轉(zhuǎn)移到LruCache緩存池中。
  • 總結(jié)
    正在使用中的圖片使用弱引用來進行緩存,暫時不用的圖片使用LruCache來進行緩存的功能;同一張圖片只會出現(xiàn)在弱引用和LruCache中的一個。這里我們也要注意到先后順序,先到弱引用,再到LruCache.
  • 這里我們可以關(guān)注一個問題:
    為什么要使用弱引用,而不是直接使用LruCache?
    1、分壓策略,減少Lrucache 中trimToSize(移除最老的數(shù)據(jù))的概率。
    2、提高效率:弱引用用的是HashMap,Lrucache用的是LinkedHashMap,從訪問效率而言,肯定是HashMap更高。
    磁盤緩存原理(DiskLruCache)

Glide磁盤緩存策略(4.x)

  • DiskCacheStrategy.DATA: 只緩存原始圖片;
  • DiskCacheStrategy.RESOURCE:只緩存轉(zhuǎn)換過后的圖片;
  • DiskCacheStrategy.ALL:既緩存原始圖片,也緩存轉(zhuǎn)換過后的圖片;對于遠(yuǎn)程圖片,緩存 DATA和 RESOURCE;對于本地圖片,只緩存 RESOURCE;
  • DiskCacheStrategy.NONE:不緩存任何內(nèi)容;
  • DiskCacheStrategy.AUTOMATIC:默認(rèn)策略,嘗試對本地和遠(yuǎn)程圖片使用最佳的策略。當(dāng)下載網(wǎng)絡(luò)圖片時,使用DATA(原因很簡單,對本地圖片的處理可比網(wǎng)絡(luò)要容易得多);對于本地圖片,使用RESOURCE。

如果在內(nèi)存緩存中沒獲取到數(shù)據(jù)會通過EngineJob開啟線程池去加載圖片,也就是剛才說的后話。
這里有2個關(guān)鍵類:DecodeJob 和EngineJob。

  • EngineJob 內(nèi)部維護了線程池,用來管理資源加載,當(dāng)資源加載完畢的時候通知回調(diào);
  • DecodeJob是線程池中的一個任務(wù)。
    磁盤緩存是通過DiskLruCache來管理的,根據(jù)不同的緩存策略,會有2種類型的圖片,DATA(原始圖片)和 RESOURCE(轉(zhuǎn)換后的圖片)。磁盤緩存依次通過ResourcesCacheGenerator、SourceGenerator、DataCacheGenerator來獲取緩存數(shù)據(jù)。
    ResourcesCacheGenerator獲取的是轉(zhuǎn)換過的緩存數(shù)據(jù);
    SourceGenerator獲取的是未經(jīng)轉(zhuǎn)換的原始的緩存數(shù)據(jù);
    DataCacheGenerator是通過網(wǎng)絡(luò)獲取圖片數(shù)據(jù)再按照按照緩存策略的不同去緩存不同的圖片到磁盤上。

總結(jié)

  • Glide緩存分為弱引用+ LruCache+ DiskLruCache,其中讀取數(shù)據(jù)的順序是:弱引用 > LruCache > DiskLruCache>網(wǎng)絡(luò);寫入緩存的順序是:網(wǎng)絡(luò) --> DiskLruCache--> 弱引用-->LruCache
  • 內(nèi)存緩存分為弱引用的和 LruCache ,其中正在使用的圖片使用弱引用緩存,暫時不使用的圖片用 LruCache緩存,這一點是通過 圖片引用計數(shù)器(acquired變量)來實現(xiàn)的。
  • 磁盤緩存就是通過DiskLruCache實現(xiàn)的,根據(jù)緩存策略的不同會獲取到不同類型的緩存圖片。
    它的邏輯是:先從轉(zhuǎn)換后的緩存中取;
    沒有的話再從原始的(沒有轉(zhuǎn)換過的)緩存中拿數(shù)據(jù);
    再沒有的話就從網(wǎng)絡(luò)加載圖片數(shù)據(jù),獲取到數(shù)據(jù)之后,再依次緩存到磁盤和弱引用。
  • 盜圖一張,再度回顧一下這個流程。


    the with.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容