前言
近期研究了一下Glide的圖片加載框架,在這里和大家分享一下。由于代碼研讀有限站蝠,難免有錯誤的地方吟孙,了解的童鞋還望指正藻治。學(xué)習(xí)小組QQ群: 193765960雏节。
本篇是Glide框架及源碼解析的第三篇件蚕,更多文章敬請關(guān)注后續(xù)文章。如果這篇文章對大家學(xué)習(xí)Glide有幫助,還望大家多多轉(zhuǎn)載。
版權(quán)歸作者所有,如有轉(zhuǎn)發(fā)泪酱,請注明文章出處:http://www.reibang.com/u/d43d948bef39
相關(guān)文章:
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(一)
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(二)
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(三)
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(四)
跟著源碼學(xué)設(shè)計(jì):Glide框架及源碼解析(五)
Glide內(nèi)存緩存機(jī)制
在之前的兩篇中我們剖析了Glide的生命周期綁定機(jī)制和Glide的請求管理機(jī)制。接下來按說應(yīng)該講到request實(shí)際請求資源并回調(diào)刷新界面這一塊了,但是為了更好的理解Glide在這一塊的設(shè)計(jì),我先大致的講一講Glide的內(nèi)存緩存和管理機(jī)制。
不同于其他常見網(wǎng)絡(luò)加載框架只有LruCatch一種緩存機(jī)制,Glide內(nèi)存為三塊(非常牛逼巧妙的設(shè)計(jì)):
- ActiveResourceCache:緩存當(dāng)前正在使用的資源(注意是弱引用)
- LruResourceCache: 緩存最近使用過但是當(dāng)前未使用的資源透敌,LRU算法
- BitmapPool:緩存所有被釋放的圖片撵术,內(nèi)存復(fù)用,LRU算法
注意:
- LruResourceCache和ActiveResourceCache設(shè)計(jì)是為了盡可能的資源復(fù)用
- BitmapPool的設(shè)計(jì)目的是為了盡可能的內(nèi)存復(fù)用
說的比較抽象古毛,是不是懵逼了?別急服傍,上圖:
當(dāng)我們需要顯示某個資源時钞支,Glide會先去查找LruResourceCache柬采,找到了則將資源從LruResourceCache移除加入到ActiveResourceCache;
LruResourceCache找不到資源則查找ActiveResourceCache。
如果在ActiveResourceCache也找不到合適的資源,則會根據(jù)加載策略從硬盤或者網(wǎng)絡(luò)加載資源力试。
獲取數(shù)據(jù)后Glide會從BitmapPool中找尋合適的可供內(nèi)存復(fù)用的廢棄recycled bitmap(找不到則會重新創(chuàng)建bitmap對象),然后刷新bitmap的數(shù)據(jù)饮亏。
bitmap被轉(zhuǎn)換封裝為Resource緩存入ActiveResourceCache和Request對象中百侧。
Request的target會獲取resource中引用的bitmap并展示。
當(dāng)target的資源需要release時突硝,resource會根據(jù)緩存策略被緩存到LruResourceCache,同時ActiveResourceCache中的弱引用會被刪除。如果拧揽,該資源不能緩存到LruResourceCache,則資源將被recycle到BitmapPool漱贱。
當(dāng)需要回收內(nèi)存時(比如系統(tǒng)內(nèi)存不足或者生命周期結(jié)束)配猫,LruResourceCache將根據(jù)LRU算法recycle一些resource到BitmapPool。
BitmapPool會根據(jù)緩存池的尺寸和recycled resource的緩存策略來緩存resource的bitmap冯丙。
BitmapPool會根據(jù)LRU算法和緩存池的尺寸來釋放一些老舊資源。
當(dāng)系統(tǒng)GC時挨厚,則會回收可回收的資源釋放內(nèi)存
這樣就完成了一個資源的完整的循環(huán)疫剃。
BitmapPool的內(nèi)存復(fù)用機(jī)制
知識儲備:
- BitmapFactory.Options.inBitmap是AndroiD3.0新增的一個屬性,如果設(shè)置了這個屬性則會重用這個Bitmap的內(nèi)存從而提升性能棉胀。
- 在SDK 11 -> 18之間,重用的bitmap大小必須是一致的诚隙,例如給inBitmap賦值的圖片大小為100-100,那么新申請的bitmap必須也為100-100才能夠被重用犯建。從SDK 19開始,新申請的bitmap大小必須小于或者等于已經(jīng)賦值過的bitmap大小瓜客。
- 新申請的bitmap與舊的bitmap必須有相同的解碼格式适瓦,例如大家都是8888的,如果前面的bitmap是8888谱仪,那么就不能支持4444與565格式的bitmap了
使用inbitmap前玻熙,內(nèi)存占用情況
使用inbitmap后疯攒,內(nèi)存占用情況
下面看一下核心代碼:Downsampler的downsampleWithSize()方法
private Bitmap downsampleWithSize(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream,
BitmapFactory.Options options, BitmapPool pool, int inWidth, int inHeight, int sampleSize,
DecodeFormat decodeFormat) {
// Prior to KitKat, the inBitmap size must exactly match the size of the bitmap we're decoding.
Bitmap.Config config = getConfig(is, decodeFormat);
options.inSampleSize = sampleSize;
options.inPreferredConfig = config;
if ((options.inSampleSize == 1 || Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) && shouldUsePool(is)) {
int targetWidth = (int) Math.ceil(inWidth / (double) sampleSize);
int targetHeight = (int) Math.ceil(inHeight / (double) sampleSize);
// BitmapFactory will clear out the Bitmap before writing to it, so getDirty is safe.
setInBitmap(options, pool.getDirty(targetWidth, targetHeight, config));
}
return decodeStream(is, bufferedStream, options);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private static void setInBitmap(BitmapFactory.Options options, Bitmap recycled) {
if (Build.VERSION_CODES.HONEYCOMB <= Build.VERSION.SDK_INT) {
options.inBitmap = recycled;
}
}
讓我們先看一下我們最常見到的LruMemoryCache機(jī)制
- 如圖,當(dāng)系統(tǒng)內(nèi)存不足時敬尺,LruMemoryCache會根據(jù)LRU算法移除一些資源(bitmap)
- 針對移除的資源枚尼,系統(tǒng)在GC時會回收資源(bitmap)以釋放內(nèi)存
- 當(dāng)應(yīng)用再次需要次資源時,需要重新分配內(nèi)存砂吞,重新對資源文件進(jìn)行解析生成bitmap
1)這樣會造成內(nèi)存抖動署恍;
2)比較耗費(fèi)時間,影響流暢度(GC也比較頻繁)
讓我們再來看一下Glide的機(jī)制
- 如圖蜻直,當(dāng)系統(tǒng)內(nèi)存不足時盯质,LruResourceCache會根據(jù)LRU算法移除一些資源(resource)到BitmapPool
- 到BitmapPool會根據(jù)LRU算法移除一些資源(bitmap)
- 當(dāng)應(yīng)用再次需要資源時,會優(yōu)先復(fù)用到BitmapPool中的bitmap對象(復(fù)用其內(nèi)存)概而,只需刷新bitmap的像素數(shù)據(jù)
1)這樣能有效地降低內(nèi)存抖動呼巷;
2)由于很多情況下可以復(fù)用廢棄bitmap的內(nèi)存,因此避免了內(nèi)存分配等造成的性能損耗赎瑰,系統(tǒng)比較流暢
3)降低了系統(tǒng)GC的頻率
4)LruResourceCache和BitmapPool中都是當(dāng)前不在使用的資源王悍,做整體的資源回收那叫一個酸爽。
(本篇是Glide框架及源碼解析的第三篇乡范,更多文章敬請關(guān)注后續(xù)文章配名。版權(quán)歸作者所有啤咽,如有轉(zhuǎn)發(fā),請注明文章出處:原文鏈接)