什么是三級緩存怔鳖?
- 內(nèi)存緩存茉唉,優(yōu)先加載,速度最快
- 本地緩存结执,次優(yōu)先加載度陆,速度快
- 網(wǎng)絡(luò)緩存,最后加載献幔,速度慢懂傀,浪費流量
為什么要進行三級緩存
三級緩存策略,最實在的意義就是減少不必要的流量消耗斜姥,增加加載速度鸿竖。
如今的 APP 網(wǎng)絡(luò)交互似乎已經(jīng)必不可少沧竟,通過網(wǎng)絡(luò)獲取圖片再正常不過了。但是缚忧,每次啟動應(yīng)用都要從網(wǎng)絡(luò)獲取圖片悟泵,或者是想重復(fù)瀏覽一些圖片的時候,每次瀏覽都需要網(wǎng)絡(luò)獲取闪水,消耗的流量就多了糕非,在如今的流量資費來說,肯定會容易影響用戶數(shù)量球榆。
還有就是網(wǎng)絡(luò)加載圖片朽肥,有時候會加載很慢,影響了用戶體驗持钉。
另外從開發(fā)角度來說衡招,Bitmap 的創(chuàng)建非常消耗時間和內(nèi)存,可能導(dǎo)致頻繁GC每强。而使用緩存策略始腾,會更加高效地加載 Bitmap,減少卡頓空执,從而減少讀取時間浪箭。
而內(nèi)存緩存的主要作用是防止應(yīng)用重復(fù)將圖片數(shù)據(jù)讀取到內(nèi)存當(dāng)中,硬盤緩存則是防止應(yīng)用重復(fù)從網(wǎng)絡(luò)或其他地方重復(fù)下載和讀取數(shù)據(jù)辨绊。
三級緩存的原理
首次加載的時候通過網(wǎng)絡(luò)加載奶栖,獲取圖片,然后保存到內(nèi)存和 SD 卡中门坷。
之后運行 APP 時宣鄙,優(yōu)先訪問內(nèi)存中的圖片緩存。
如果內(nèi)存沒有拜鹤,則加載本地 SD 卡中的圖片框冀。
具體的緩存策略可以是這樣的:內(nèi)存作為一級緩存,本地作為二級緩存敏簿,網(wǎng)絡(luò)加載為最后明也。其中,內(nèi)存使用 LruCache 惯裕,其內(nèi)部通過 LinkedhashMap 來持有外界緩存對象的強引用温数;對于本地緩存,使用 DiskLruCache蜻势。加載圖片的時候撑刺,首先使用 LRU 方式進行尋找,找不到指定內(nèi)容握玛,按照三級緩存的方式够傍,進行本地搜索甫菠,還沒有就網(wǎng)絡(luò)加載。
圖片緩存代碼實現(xiàn)
自己實現(xiàn)一個三級緩存的工具類并不困難冕屯。大概可以這樣:
public class BitmapUtil{
//單例模式
//···
public void displayImage(ImageView img, String url){
Bitmap bitmap;
//內(nèi)存緩存寂诱,url做唯一標(biāo)識符
bitmap = loadBitmapFromMemoryCache(url);
if(bitmap != null){
img.setImageBitmap(bitmap);
return ;
}
//本地緩存
bitmap = loadBitmapFromDiskCache(url);
if(bitmap != null){
img.setImageBitmap(bitmap);
//然后將本地緩存保存到內(nèi)存緩存中
return ;
}
//網(wǎng)絡(luò)緩存
bitmap = loadBitmapFromNet(url);
if(bitmap != null){
img.setImageBitmap(bitmap);
//同理將緩存保存到內(nèi)存和本地中
return;
}
}
}
詳細不說了,網(wǎng)上有很多類似的文章可以參考安聘。
關(guān)于內(nèi)存緩存的實現(xiàn)核心基本就是獲取APP最大內(nèi)存痰洒,然后set的時候用LruCache< url , bitmap>
put 進去。他會按照最近最少使用的算法將內(nèi)存控制在一定大小內(nèi)浴韭,超出的時候自動回收丘喻。
還有一點注意的是,一般url作為 key 的時候念颈,會用MD5算法處理一下泉粉,最后是用其 MD5 值作為key的,這可能是為了避免一些特殊字符影響使用舍肠。
關(guān)于Glide的緩存
事實上搀继,現(xiàn)在已經(jīng)很少自己封裝一個三級緩存策略,在眾多的圖片框架中都加入緩存策略翠语,實現(xiàn)起來更簡單。這里以 Glide 為例财边。
Glide 的使用基本就是一行代碼就解決了肌括。像下面這樣
// 加載本地圖片
File file = new File(getExternalCacheDir() + "/image.jpg");
Glide.with(this).load(file).into(imageView);
// 加載應(yīng)用資源
int resource = R.drawable.image;
Glide.with(this).load(resource).into(imageView);
// 加載二進制流
byte[] image = getImageBytes();
Glide.with(this).load(image).into(imageView);
// 加載Uri對象
Uri imageUri = getImageUri();
Glide.with(this).load(imageUri).into(imageView);
當(dāng)然應(yīng)用到項目里面最好二次封裝一下。這些不是這次文章的主題酣难。我們回到緩存上面來谍夭。
Glide 的內(nèi)存緩存
Glide 是默認(rèn)開啟了內(nèi)存緩存的,只要你通過 Glide 加載一張圖片憨募,他就會緩存到內(nèi)存中紧索,只要他還沒被從內(nèi)存中清理之前,下次使用 Glide 都會從內(nèi)存緩存中加載菜谣。大大提升了圖片加載的效率珠漂。
當(dāng)然如果你有特殊要求,可以添加一行代碼把默認(rèn)開啟的內(nèi)存緩存關(guān)閉掉尾膊。
Glide.with(this)
.load(url)
.skipMemoryCache(true)//關(guān)閉內(nèi)存緩存
.into(imageView);
Glide 的內(nèi)存緩存實際上和我們上面說的差別不大媳危,使用的也是LruCache算法,不過他還結(jié)合了一種弱引用機制冈敛,共同完成了內(nèi)存緩存功能待笑。
詳情可以看文末參考文章郭霖大神關(guān)于Glide源碼的解析。
Glide 的硬盤緩存
關(guān)于 Glide 硬盤緩存使用也是十分簡單抓谴。
Glide.with(this)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.into(imageView);
一個 diskCacheStrategy( ) 方法就可以調(diào)整他的硬盤緩存策略暮蹂。其中可以傳入的參數(shù)有四種:
- DiskCacheStrategy.NONE: 表示不緩存任何內(nèi)容寞缝。
- DiskCacheStrategy.SOURCE: 表示只緩存原始圖片。
- DiskCacheStrategy.RESULT: 表示只緩存轉(zhuǎn)換過后的圖片(默認(rèn)選項)仰泻。
- DiskCacheStrategy.ALL : 表示既緩存原始圖片荆陆,也緩存轉(zhuǎn)換過后的圖片。
Glide 的硬盤緩存是默認(rèn)將圖片壓縮轉(zhuǎn)換后再緩存到硬盤中我纪,這種處理方式再避免OOM的時候會經(jīng)成鞅觯看見。
如果需要改變硬盤緩存策略只需要改變其傳入的參數(shù)即可浅悉。
參考文章:
- Android圖片加載框架最全解析(三)趟据,深入探究Glide的緩存機制 —— 郭霖
- Android中圖片的三級緩存—— wanbo_