Glide 快取與解碼複用
Glide 使用簡明的流式語法API,大多數情況下,可能完成圖片的設定你只需要:
Glide.with(activity) .load(url) .into(imageView);
預設情況下,Glide 會在開始一個新的圖片請求之前檢查以下多級的快取:
1. 活動資源 (Active Resources)
2. 記憶體快取 (Memory Cache)
3. 資源型別(Resource Disk Cache)
4. 原始資料 (Data Disk Cache)
活動資源:如果當前對應的圖片資源正在使用,則這個圖片會被Glide放入活動快取。
記憶體快取:如果圖片最近被載入過,並且當前沒有使用這個圖片,則會被放入記憶體中
資源型別: 被解碼後的圖片寫入磁碟檔案中,解碼的過程可能修改了圖片的引數(如:inSampleSize 、inPreferredConfig)
原始資料: 圖片原始資料在磁碟中的快取(從網路、檔案中直接獲得的原始資料)
複製程式碼
在呼叫into之後,Glide會首先從Active Resources查詢當前是否有對應的活躍圖片,沒有則查詢記憶體快取,沒有則查詢資源型別,沒有則查詢資料來源。
快取查詢.png
相較於常見的記憶體+磁碟快取,Glide將其快取分成了4層。
第一層 活動資源
當需要載入某張圖片能夠從記憶體快取中獲得的時候,在圖片載入時主動將對應圖片從記憶體快取中移除,加入到活動資源中。
這樣也可以避免因為達到記憶體快取最大值或者系統記憶體壓力導致的記憶體快取清理,從而釋放掉活動資源中的圖片(recycle)。
活動資源中是一個”引用計數"的圖片資源的弱引用集合。
第二層 記憶體快取
記憶體快取預設使用LRU(快取淘汰演算法/最近最少使用演算法),當資源從活動資源移除的時候,會加入此快取。使用圖片的時候會主動從此快取移除,加入活動資源。
構造LinkedHashMap的accessOrder設定為true。在使用的此map的時候,自動進行排序(每次get/put,會將使用的value放入連結串列header頭部)。LruCache會在每次get/put的時候判斷資料如果達到了maxSize,則會優先刪除tail尾端的資料。
LRU.png
磁碟快取同樣使用LRU演算法。
第三、四層 磁碟快取
Resource 快取的是經過解碼後的圖片,如果再使用就不需要再去進行解碼配置(BitmapFactory.Options),加快獲得圖片速度。比如原圖是一個100x100的ARGB_8888圖片,在首次使用的時候需要的是50x50的RGB_565圖片,那麼Resource將50x50 RGB_565快取下來,再次使用此圖片的時候就可以從 Resource 獲得。不需要去計算inSampleSize(縮放因子)。
Data 快取的則是影象原始資料。
Bitmap複用
如果快取都不存在,那麼會從源地址獲得圖片(網路/檔案)。而在解析圖片的時候會需要可以獲得BitmapPool(複用池),達到複用的效果。
複用前.png
複用後.png
複用效果如上。在未使用複用的情況下,每張圖片都需要一塊記憶體。而使用複用的時候,如果存在能被複用的圖片會重複使用該圖片的記憶體。所以複用並不能減少程式正在使用的記憶體大小。Bitmap複用,解決的是減少頻繁申請記憶體帶來的效能(抖動、碎片)問題。
developer.android.google.cn/topic/perfo… 設定inBitmap複用.png 獲得可複用Bitmap.png 檢查Bitmap是否可複用.png
Google給出的案例可以看出:
使用方式為在解析的時候設定Options的inBitmap屬性。
- Bitmap的inMutable需要為true。
- Android 4.4及以上只需要被複用的Bitmap的記憶體必須大於等於需要新獲得Bitmap的記憶體,則允許複用此Bitmap。
- 4.4以下(3.0以上)則被複用的Bitmap與使用複用的Bitmap必須寬、高相等並且使用複用的Bitmap解碼時設定的inSampleSize為1,才允許複用。
因此Glide中,在每次解析一張圖片為Bitmap的時候(磁碟快取、網路/檔案)會從其BitmapPool中查詢一個可被複用的Bitmap。
BitmapPool是Glide中的Bitmap複用池,同樣適用LRU來進行管理。
當一個Bitmap從記憶體快取 被動 的被移除(記憶體緊張、達到maxSize)的時候並不會被recycle。而是加入這個BitmapPool,只有從這個BitmapPool 被動
被移除的時候,Bitmap的記憶體才會真正被recycle釋放。