前言
-
Glide
抽活,該功能非常強大Android
圖片加載開源框架 相信大家并不陌生
Github截圖 正由于他的功能強大组橄,所以它的源碼非常復(fù)雜孕惜,這導(dǎo)致很多人望而卻步
本人嘗試將
Glide
的功能進(jìn)行分解,并單獨針對每個功能進(jìn)行源碼分析晨炕,從而降低Glide
源碼的復(fù)雜度衫画。
接下來,我將推出一系列關(guān)于
Glide
的功能源碼分析瓮栗,有興趣可以繼續(xù)關(guān)注
- 今天削罩,我將主要講解在使用
Glide
緩存功能時的問題:為什么Glide 的緩存無起作用,希望你們會喜歡费奸。
1. 背景
-
Glide
實現(xiàn)內(nèi)存 & 磁盤緩存是根據(jù) 圖片的緩存Key
進(jìn)行唯一標(biāo)識 - 開發(fā)者為了降低成本 & 安全弥激,往往會將圖片存放在云服務(wù)器上
如 七牛云 等等。
- 為了保護(hù) 客戶的圖片資源愿阐,圖片云服務(wù)器 會在圖片
Url
地址的基礎(chǔ)上再加一個token參數(shù)
http://url.com/image.jpg?token=a6cvva6b02c670b0a
-
Glide
加載該圖片時微服,會使用加了token
參數(shù)的圖片Url
地址 作為
id
參數(shù),從而生成 緩存Key
2. 問題
- 作為身份認(rèn)證的
token
參數(shù)可能會發(fā)生變化缨历,并不是一成不變 - 若
token
參數(shù)變了以蕴,則圖片Url
跟著變,則生成緩存key的所需id參數(shù)發(fā)生變化辛孵,即 緩存Key也會跟著變化 - 這導(dǎo)致同一張圖片丛肮,但因為
token
參數(shù)變化,而導(dǎo)致緩存Key發(fā)生變化魄缚,從而使得Glide
的緩存功能失效
緩存Key發(fā)生變化宝与,即同一個圖片的當(dāng)前緩存key 和 之前寫入緩存的key不相同焚廊,這意味著 在讀取緩存時 無法根據(jù)當(dāng)前緩存key 找到之前的緩存,從而使得失效
3. 解決方案
3.1 原理
在 生成緩存Key
的id參數(shù) 前习劫,將 帶有token
參數(shù)的圖片Url
地址 去掉 token
參數(shù)咆瘟,從而根據(jù) 初始的圖片Url
地址 生成緩存Key
的id參數(shù)
實現(xiàn)了一個圖片的緩存
Key
的id參數(shù)始終唯一 ,即等于 圖片Url
地址
3.2 儲備知識:生成緩存Key的id參數(shù)的邏輯
生成緩存Key
的id
參數(shù)的邏輯為:直接將圖片的 URL
地址作為緩存Key的id
參數(shù)
回看文章:Android:手把手帶你深入圖片加載庫Glide源碼分析生成緩存
Key
的代碼
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
Util.assertMainThread();
long startTime = LogTime.getLogTime();
final String id = fetcher.getId();
// 獲得了一個id字符串诽里,即需加載圖片的唯一標(biāo)識
// 如搞疗,若圖片的來源是網(wǎng)絡(luò),那么該id = 這張圖片的url地址
// fetcher = HttpUrlFetcher的實例须肆,即調(diào)用HttpUrlFetcher.getid()->>分析19
EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),transcoder, loadProvider.getSourceEncoder());
// 將該id 和 signature匿乃、width、height等10個參數(shù)一起傳入到緩存Key的工廠方法里豌汇,最終創(chuàng)建出一個EngineKey對象
// 創(chuàng)建原理:通過重寫equals() 和 hashCode()幢炸,保證只有傳入EngineKey的所有參數(shù)都相同情況下才認(rèn)為是同一個EngineKey對象
// 該EngineKey 即Glide中的緩存Key
...
}
<-- 分析19:getId() -->
public class HttpUrlFetcher implements DataFetcher<InputStream> {
...
private final GlideUrl glideUrl;
// GlideUrl = 在上篇文章講解 圖片加載 第2步load()中傳入圖片url地址時,Glide在內(nèi)部把圖片url地址包裝成一個GlideUrl對象
@Override
public String getId() {
return glideUrl.getCacheKey();
// ->>分析20
}
<-- 分析20:getCacheKey() -->
public class GlideUrl {
private final URL url;
private final String stringUrl;
...
// GlideUrl構(gòu)造函數(shù)
public GlideUrl(URL url) {
this(url, Headers.DEFAULT);
}
public GlideUrl(String url) {
this(url, Headers.DEFAULT);
}
public String getCacheKey() {
return stringUrl != null ? stringUrl : url.toString();
// 在生成GlideUrl對象時:
// 若傳入的是URL字符串(即圖片地址)拒贱,就直接返回該字符串(大多數(shù)是這種情況)
// 若傳入的是URL對象宛徊,那么就返回這個對象toString()后的結(jié)果。
}
...
}
3.3 實現(xiàn)方案
即 我們只需重寫getCacheKey()
& 將 帶有token參數(shù)的圖片Url
地址 去掉 token參數(shù) 即可逻澳。
/**
* 代碼實現(xiàn):創(chuàng)建一個GlideUrl類的子類 & 重寫getCacheKey()
**/
// 1. 繼承GlideUrl
public class mGlideUrl extends GlideUrl {
private String mUrl;
// 構(gòu)造函數(shù)里 傳入 帶有token參數(shù)的圖片Url地址
public MyGlideUrl(String url) {
super(url);
mUrl = url;
}
// 2. 重寫getCacheKey()
@Override
public String getCacheKey() {
return mUrl.replace(deleteToken(), "");
// 通過 deleteToken() 從 帶有token參數(shù)的圖片Url地址中 去掉 token參數(shù)
// 最終返回一個沒有token參數(shù)闸天、初始的圖片URL地址
// ->>分析1
}
// 分析1:deleteToken()
private String deleteToken() {
String tokenParam = "";
int tokenKeyIndex = mUrl.indexOf("?token=") >= 0 ? mUrl.indexOf("?token=") : mUrl.indexOf("&token=");
if (tokenKeyIndex != -1) {
int nextAndIndex = mUrl.indexOf("&", tokenKeyIndex + 1);
if (nextAndIndex != -1) {
tokenParam = mUrl.substring(tokenKeyIndex + 1, nextAndIndex + 1);
} else {
tokenParam = mUrl.substring(tokenKeyIndex);
}
}
return tokenParam;
}
}
/**
* 使用緩存時:需要在load()中傳入自定義的 mGlideUrl對象
**/
Glide.with(this)
.load(new mGlideUrl(url))
.into(imageView);
// 注:a. 若像之前直接傳入圖片的url地址,那么在內(nèi)部還是會使用原始的GlideUrl類
// b. 即直接將傳入傳入圖片的url地址作為緩存key的Id參數(shù)斜做,而沒有對token參數(shù)作任何處理
4. 總結(jié)
本文主要對Glide
的圖片緩存功能的使用問題進(jìn)行講解
Carson帶你學(xué)Android開源庫系列文章:
Carson帶你學(xué)Android:主流開源圖片加載庫對比(UIL苞氮、Picasso、Glide瓤逼、Fresco)
Carson帶你學(xué)Android:主流開源網(wǎng)絡(luò)請求庫對比(Volley笼吟、OkHttp、Retrofit)
Carson帶你學(xué)Android:網(wǎng)絡(luò)請求庫Retrofit使用教程
Carson帶你學(xué)Android:網(wǎng)絡(luò)請求庫Retrofit源碼分析
Carson帶你學(xué)Android:圖片加載庫Glide使用教程
Carson帶你學(xué)Android:圖片加載庫Glide源碼分析
Carson帶你學(xué)Android:V-Layout霸旗,淘寶贷帮、天貓都在用的UI框架,趕緊用起來吧诱告!
歡迎關(guān)注Carson_Ho的簡書
不定期分享關(guān)于安卓開發(fā)的干貨撵枢,追求短、平精居、快锄禽,但卻不缺深度。