Android Glide 里的緩存

Glide 里的緩存

默認(rèn)情況下,Glide 會(huì)在開始一個(gè)新的圖片請(qǐng)求之前檢查多級(jí)緩存:

  • 1、活動(dòng)資源(Activity Resource)- 現(xiàn)在是否有一個(gè) View 正在展示這張圖片?
  • 2、內(nèi)存緩存(Memory cache)- 該圖片是否最近被加載過(guò)并仍然存在內(nèi)存中?
  • 3、資源類型(Resource)- 該圖片是否之前曾被解碼,轉(zhuǎn)換并寫入過(guò)磁盤緩存?
  • 4、數(shù)據(jù)來(lái)源(Data)- 構(gòu)建這個(gè)圖片的資源是否之前曾被寫入過(guò)文件緩存?

前兩步檢查圖片是否存在內(nèi)存中,如果是則直接返回圖片。后兩步則檢查圖片是否在磁盤上,一遍快速異步的返回圖片。
如果四個(gè)步驟都未能找到圖片,則Glide會(huì)返回到原始資源以取回?cái)?shù)據(jù)(原始文件,Uri, Url等)。
關(guān)于 Glide 緩存的默認(rèn)大小與它們?cè)诖疟P上的位置的更多細(xì)節(jié),或如何配置這些參數(shù),請(qǐng)查看 配置 頁(yè)面。

緩存鍵 (Cache Keys)

在 Glide v4 里,所有緩存鍵都包含至少兩個(gè)元素:

  • 1、請(qǐng)求加載的 model(File, Uri, Url)。如果你使用自定義的 model, 它需要正確地實(shí)現(xiàn) hashCode() 和 equals()
  • 2、一個(gè)可選的 簽名(Signature)
    另外,步驟 1-3 (活動(dòng)資源、內(nèi)存緩存、資源磁盤緩存)的緩存鍵還包括一些其他的數(shù)據(jù),包括:
  • 1、寬度和高度
  • 2、可選的變換(Transformation)
  • 3、額外添加的任何選項(xiàng)(Options)
  • 4、請(qǐng)求的數(shù)據(jù)類型(Bitmap,GIF或者其他)
    活動(dòng)資源和內(nèi)存緩存使用的鍵還和磁盤資源緩存略有不同,以適應(yīng)內(nèi)存 選項(xiàng)(Options),比如影響 Bitmap 配置的選項(xiàng)或其他解碼時(shí)才會(huì)用到的參數(shù)。

為了生成磁盤緩存上的緩存鍵名稱,以上的每個(gè)元素會(huì)被哈?;詣?chuàng)建一個(gè)單獨(dú)的字符串鍵名,并在隨后作為磁盤緩存上的文件名使用。

配置緩存

Glide 提供一系列的選項(xiàng),以允許你選擇加載請(qǐng)求與 Glide 緩存如何交互。

磁盤緩存策略(Disk Cache Strategy)

DiskCacheStrategy 可被 diskCacheStrategy 方法應(yīng)用到每一個(gè)單獨(dú)的請(qǐng)求。 目前支持的策略允許你阻止加載過(guò)程使用或?qū)懭氪疟P緩存,選擇性地僅緩存無(wú)修改的原生數(shù)據(jù),或僅緩存變換過(guò)的縮略圖,或是兼而有之。
默認(rèn)的策略叫做 AUTOMATIC ,它會(huì)嘗試對(duì)本地和遠(yuǎn)程圖片使用最佳的策略。當(dāng)你加載遠(yuǎn)程數(shù)據(jù)(比如,從URL下載)時(shí),AUTOMATIC 策略僅會(huì)存儲(chǔ)未被你的加載過(guò)程修改過(guò)(比如,變換,裁剪–譯者注)的原始數(shù)據(jù),因?yàn)橄螺d遠(yuǎn)程數(shù)據(jù)相比調(diào)整磁盤上已經(jīng)存在的數(shù)據(jù)要昂貴得多。對(duì)于本地?cái)?shù)據(jù),AUTOMATIC 策略則會(huì)僅存儲(chǔ)變換過(guò)的縮略圖,因?yàn)榧词鼓阈枰俅紊闪硪粋€(gè)尺寸或類型的圖片,取回原始數(shù)據(jù)也很容易。
指定 DiskCacheStrategy 非常容易:

Glide.with(fragment)
  .load(url)
  .diskCacheStrategy(DiskCacheStrategy.ALL)
  .into(imageView);

僅從緩存加載圖片

某些情形下,你可能希望只要圖片不在緩存中則加載直接失?。?em>比如省流量模式)。如果要完成這個(gè)目標(biāo),你可以在單個(gè)請(qǐng)求的基礎(chǔ)上使用 onlyRetrieveFromCache 方法:

Glide.with(fragment)
  .load(url)
  .onlyRetrieveFromCache(true)
  .into(imageView);

如果圖片在內(nèi)存緩存或在磁盤緩存中,它會(huì)被展示出來(lái)。否則只要這個(gè)選項(xiàng)被設(shè)置為 true ,這次加載會(huì)視同失敗。

跳過(guò)緩存

如果你想確保一個(gè)特定的請(qǐng)求跳過(guò)磁盤和/或內(nèi)存緩存(比如,圖片驗(yàn)證碼),Glide 也提供了一些替代方案。

僅跳過(guò)內(nèi)存緩存,請(qǐng)使用 skipMemoryCache() :

Glide.with(fragment)
  .load(url)
  .skipMemoryCache(true)
  .into(view);

僅跳過(guò)磁盤緩存,請(qǐng)使用 DiskCacheStrategy.NONE :

Glide.with(fragment)
  .load(url)
  .diskCacheStrategy(DiskCacheStrategy.NONE)
  .into(view);

這兩個(gè)選項(xiàng)可以同時(shí)使用:

Glide.with(fragment)
  .load(url)
  .diskCacheStrategy(DiskCacheStrategy.NONE)
  .skipMemoryCache(true)
  .into(view);

雖然提供了這些辦法讓你跳過(guò)緩存,但你通常應(yīng)該不會(huì)想這么做。從緩存中加載一個(gè)圖片,要比拉取-解碼-轉(zhuǎn)換成一張新圖片的完整流程快得多。

如果你只是想更新緩存中的某個(gè)條目,請(qǐng)繼續(xù)閱讀下面關(guān)于 invalidation 介紹。

實(shí)現(xiàn)

如果內(nèi)置的選項(xiàng)不滿足你的需求,你也可以編寫你自己的 DiskCache 實(shí)現(xiàn)。請(qǐng)查看 配置 頁(yè)獲得更多信息。

緩存的刷新

因?yàn)榇疟P緩存使用的是哈希鍵,所以并沒有一個(gè)比較好的方式來(lái)簡(jiǎn)單地刪除某個(gè)特定 url 或文件路徑對(duì)應(yīng)的所有緩存文件。如果你只允許加載或緩存原始圖片的話,問(wèn)題可能會(huì)變得更簡(jiǎn)單,但因?yàn)?Glide 還會(huì)緩存縮略圖和提供多種變換 (transformation),它們中的任何一個(gè)都會(huì)導(dǎo)致在緩存中創(chuàng)建一個(gè)新的文件,而要跟蹤和刪除一個(gè)圖片的所有版本無(wú)疑是困難的。
在實(shí)踐中,使緩存文件無(wú)效的最佳方式是在內(nèi)容發(fā)生變化時(shí)(url,uri,文件路徑等)更改你的標(biāo)識(shí)符。

定制緩存的刷新策略

因?yàn)橥ǔ8淖儤?biāo)識(shí)符比較困難或者根本不可能,所以Glide也提供了 簽名 API 來(lái)混合(你可以控制的)額外數(shù)據(jù)到你的緩存鍵中。簽名(signature)適用于媒體內(nèi)容,也適用于你可以自行維護(hù)的一些版本元數(shù)據(jù)。

  • MediaStore 內(nèi)容 - 對(duì)于媒體存儲(chǔ)內(nèi)容,你可以使用Glide的 MediaStoreSignature 類作為你的簽名。MediaStoreSignature 允許你混入修改時(shí)間、MIME類型,以及item的方向到緩存鍵中。這三個(gè)屬性能夠可靠地捕獲對(duì)圖片的編輯和更新,這可以允許你緩存媒體存儲(chǔ)的縮略圖。
  • 文件 - 你可以使用 ObjectKey 來(lái)混入文件的修改日期。
  • Url - 盡管最好的讓 url 失效的辦法是讓 server 保證在內(nèi)容變更時(shí)對(duì)URL做出改變,你仍然可以使用 ObjectKey 來(lái)混入任意數(shù)據(jù)(比如版本號(hào))。
    將簽名傳入加載請(qǐng)求很簡(jiǎn)單:
Glide.with(yourFragment)
    .load(yourFileDataModel)
    .signature(new ObjectKey(yourVersionMetadata))
    .into(yourImageView);

媒體存儲(chǔ)簽名對(duì)于 MediaStore 數(shù)據(jù)來(lái)說(shuō)也很直接:

Glide.with(fragment)
    .load(mediaStoreUri)
    .signature(new MediaStoreSignature(mimeType, dateModified, orientation))
    .into(view);

你還可以定義你自己的簽名,只要實(shí)現(xiàn) Key 接口就好。請(qǐng)確保正確地實(shí)現(xiàn) equals(), hashCode()updateDiskCacheKey() 方法:

public class IntegerVersionSignature implements Key {
    private int currentVersion;

    public IntegerVersionSignature(int currentVersion) {
         this.currentVersion = currentVersion;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof IntegerVersionSignature) {
            IntegerVersionSignature other = (IntegerVersionSignature) o;
            return currentVersion == other.currentVersion;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return currentVersion;
    }

    @Override
    public void updateDiskCacheKey(MessageDigest md) {
        messageDigest.update(ByteBuffer.allocate(Integer.SIZE).putInt(signature).array());
    }
}

請(qǐng)記住,為了避免降低性能,您將需要在后臺(tái)批量加載任何版本元數(shù)據(jù),以便在要加載圖像時(shí)即已處于可用狀態(tài)。

如果這些努力都無(wú)法奏效,您不能更改標(biāo)識(shí)符,也不能跟蹤任何合理的版本元數(shù)據(jù)的情況下,也可以使用 diskCacheStrategy()DiskCacheStrategy.NONE 來(lái)完全禁用磁盤緩存。

資源管理

Glide 的磁盤和內(nèi)存緩存都是 LRU ,這意味著在達(dá)到使用限制或持續(xù)接近限制值之前,它們將占用持續(xù)增加的內(nèi)存或磁盤空間。為了增加額外的靈活性,Glide 提供了一些額外的方式來(lái)讓你可以管理你的應(yīng)用使用的資源。
請(qǐng)記住,更大的內(nèi)存緩存、位圖池和磁盤緩存通常能提供更好的性能,或者至少在同等級(jí)別。如果你改變了緩存的大小, 你應(yīng)該小心地測(cè)量一下你改動(dòng)之前和之后的性能對(duì)比,以確保你的修改帶來(lái)的性價(jià)比是可以接受的。

內(nèi)存緩存

默認(rèn)情況下 Glide 的內(nèi)存緩存和 BitmapPool 會(huì)響應(yīng) ComponentCallback2 ,并根據(jù) Android framework 提供的級(jí)別自動(dòng)清理內(nèi)容。 因此你通常不需要嘗試動(dòng)態(tài)監(jiān)視或清理你的緩存或 BitmapPool。然而,如果必要的話,Glide 確實(shí)提供了幾個(gè)手動(dòng)選項(xiàng)。

永久尺寸調(diào)整

要改變你應(yīng)用中 Glide 的可用 RAM 大小,請(qǐng)查看 配置。

暫時(shí)尺寸

要在你應(yīng)用的特定部分暫時(shí)允許 Glide 使用更多或更少的內(nèi)存,你可以使用 setMemoryCategory:

// This method must be called on the main thread.
Glide.get(context).clearMemory();

清理所有內(nèi)存并非特別經(jīng)濟(jì),并且應(yīng)該盡可能避免,以避免出現(xiàn)抖動(dòng)和增加加載時(shí)間。

磁盤緩存

Glide 在運(yùn)行時(shí)僅提供對(duì)磁盤緩存的有限控制,但是其大小和配置可以在 AppGlideModule 中改變。

永久尺寸修改

要改變你應(yīng)用中 Glide 可用的 sdcard 可用空間,請(qǐng)查看 配置。

清理磁盤緩存

要嘗試清理所有磁盤緩存條目,你可以使用 clearDiskCache。

new AsyncTask<Void, Void, Void> {
  @Override
  protected Void doInBackground(Void... params) {
    // This method must be called on a background thread.
    Glide.get(applicationContext).clearDiskCache();
    return null;
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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