本篇內(nèi)容介紹了“怎么使用Glide的LruCache”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
成都創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于做網(wǎng)站、成都做網(wǎng)站、田家庵網(wǎng)絡(luò)推廣、微信小程序開發(fā)、田家庵網(wǎng)絡(luò)營銷、田家庵企業(yè)策劃、田家庵品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎;成都創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供田家庵建站搭建服務(wù),24小時服務(wù)熱線:028-86922220,官方網(wǎng)址:www.cdcxhl.com
使用方法及結(jié)果
在項(xiàng)目中直接導(dǎo)入Glide的庫,調(diào)用內(nèi)部的LruCache來看看效果。
LruCache lruCache = new LruCache(2); lruCache.put("1", 1); lruCache.put("2", 2); lruCache.put("1", 1); lruCache.put("3", 3); System.out.println(lruCache.get("1")); System.out.println(lruCache.get("2")); System.out.println(lruCache.get("3"));
簡要說明代碼內(nèi)容,創(chuàng)建一個空間為2的存儲空間(這里先不透漏內(nèi)部結(jié)構(gòu)),用put()方法對數(shù)據(jù)進(jìn)行存儲,再通過get()對每個數(shù)據(jù)進(jìn)行一次獲取操作,然后我們再來看看結(jié)果。
我的天!!2沒了? 這是怎么一回事??為了知道答案,那我們只好進(jìn)入Glide的庫中看看原因了。
LruCache源碼導(dǎo)讀
先看看LruCache的變量家庭里有哪些小家伙把。
public class LruCache{ // 容量為100的雙向鏈表 private final Map cache = new LinkedHashMap<>(100, 0.75f, true); private final long initialMaxSize; // 初始化最大容量 private long maxSize; // 最大容量 private long currentSize; // 已存在容量 }
同樣對于LruCache來說不也和HashMap一樣只有三步驟要走嘛,那我就從這三個步驟入手探索一下LruCache好了,但是我們要帶上一個問題出發(fā),initialMaxSize的作用是什么?
new LruCache
public LruCache(long size) { this.initialMaxSize = size; this.maxSize = size; }
到這里想來讀者都已經(jīng)知道套路了,也就初始化了初始化最大容量和最大容量,那就直接下一步。
put(key, value)
public synchronized Y put(@NonNull T key, @Nullable Y item) { // 返回值就是一個1 final int itemSize = getSize(item); // 如果1大于等于最大值就無操作 // 也就說明整個初始化的時候并不能將size設(shè)置成1 if (itemSize >= maxSize) { //用于重寫的保留方法 onItemEvicted(key, item); return null; } // 對當(dāng)前存在數(shù)據(jù)容量加一 if (item != null) { currentSize += itemSize; } @Nullable final Y old = cache.put(key, item); if (old != null) { currentSize -= getSize(old); if (!old.equals(item)) { onItemEvicted(key, old); } } evict(); // 1 --> return old; } // 由注釋1直接調(diào)用的方法 private void evict() { trimToSize(maxSize); // 2 --> } // 由注釋2直接調(diào)用的方法 protected synchronized void trimToSize(long size) { Map.Entrylast; Iterator > cacheIterator; // 說明當(dāng)前的容量大于了最大容量 // 需要對最后的數(shù)據(jù)進(jìn)行一個清理 while (currentSize > size) { cacheIterator = cache.entrySet().iterator(); last = cacheIterator.next(); final Y toRemove = last.getValue(); currentSize -= getSize(toRemove); final T key = last.getKey(); cacheIterator.remove(); onItemEvicted(key, toRemove); } }
這是一個帶鎖機(jī)制的方法,通過對當(dāng)前容量和最大容量的判斷,來抉擇是否需要把我們的數(shù)據(jù)進(jìn)行一個刪除。但是問題依舊存在,initialMaxSize的作用是什么?,我們能夠知道的是maxSize是一個用于控制容量大小的值。
get()
public synchronized Y get(@NonNull T key) { return cache.get(key); }
那這就是調(diào)用了LinkedHashMap中的數(shù)據(jù),但是終究還是沒有說出initialMaxSize的作用。
關(guān)于initialMaxSize
這里就不買關(guān)子了,因?yàn)槠鋵?shí)就我的視角來看這個initialMaxSize確實(shí)是沒啥用處的。哈哈哈哈哈!!!但是,又一個地方用到了它。
public synchronized void setSizeMultiplier(float multiplier) { if (multiplier < 0) { throw new IllegalArgumentException("Multiplier must be >= 0"); } maxSize = Math.round(initialMaxSize * multiplier); evict(); }
也就是用于調(diào)控我們的最大容量大小,但是我覺得還是沒啥用,可是是我太菜了吧,這個方法沒有其他調(diào)用它的方法,是一個我們直接在使用過程中使用的,可能和數(shù)據(jù)多次使用的一個保存之類的問題相關(guān)聯(lián)把,場景的話也就類似Glide的圖片緩存加載把。也希望知道的讀者能給我一個解答。
LinkedHashMap
因?yàn)椴僮鞣绞胶虷ashMap一致就不再復(fù)述,就看看他的節(jié)點(diǎn)長相。
static class LinkedHashMapEntryextends HashMap.Node { // 存在前后節(jié)點(diǎn),也就是我們所說的雙向鏈表 LinkedHashMapEntry before, after; LinkedHashMapEntry(int hash, K key, V value, Node next) { super(hash, key, value, next); } }
但是到這里,我又出現(xiàn)了一個問題,為什么我沒有看到整個數(shù)據(jù)的移動?也就是最近使用的數(shù)據(jù)應(yīng)該調(diào)換到最后開始的位置,他到底實(shí)在哪里進(jìn)行處理的呢?做一個猜想好了,既然是使用了put()才會造成雙向鏈表中數(shù)據(jù)的變換,那我們就應(yīng)該是需要進(jìn)入對LinkedHashMap.put()方法中進(jìn)行查詢。
當(dāng)然有興趣探索的讀者們,我需要提一個醒,就是這次的調(diào)用不可以直接進(jìn)行對put()進(jìn)行查詢,那樣只會調(diào)用到一個接口函數(shù),或者是抽象類函數(shù),最適合的方法還是使用我們的斷點(diǎn)來進(jìn)行探索查詢。
但是經(jīng)過一段努力后,不斷深度調(diào)用探索發(fā)現(xiàn)這樣的問題,他最后會調(diào)用到這樣的問題。
// Callbacks to allow LinkedHashMap post-actions void afterNodeAccess(Nodep) { } // 把數(shù)據(jù)移動到最后一位 void afterNodeInsertion(boolean evict) { } void afterNodeRemoval(Node p) { }
這是之前我們在了解HashMap是并沒有發(fā)現(xiàn)幾個方法,上面也明確寫著為LinkedHashMap保留。哇哦!!那我們的操作肯定實(shí)在這些里面了。
// --> HashMap源碼第656行附近調(diào)用到下方方法 // 在putVal()方法內(nèi)部存在這個出現(xiàn) afterNodeAccess(e); // --> LinkedHashMap對其具體實(shí)現(xiàn) // 就是將當(dāng)前數(shù)據(jù)直接推到最后一個位置 // 也就是成為了最近剛使用過的數(shù)據(jù) void afterNodeAccess(Nodee) { // move node to last LinkedHashMapEntry last; if (accessOrder && (last = tail) != e) { LinkedHashMapEntry p = (LinkedHashMapEntry )e, b = p.before, a = p.after; p.after = null; if (b == null) head = a; else b.after = a; if (a != null) a.before = b; else last = b; if (last == null) head = p; else { p.before = last; last.after = p; } tail = p; ++modCount; } }
好了,自此我們也就清楚了整個鏈表的變換過程了。
實(shí)戰(zhàn):手?jǐn)]LruCache
這是一個非常緊張刺激的環(huán)節(jié)了,擼代碼前,我們來找找思路好了。
(1)存儲容器用什么? 因?yàn)長inkedHashMap的思路太過冗長,我們用數(shù)組來重新完成整個代碼的構(gòu)建
(2)關(guān)鍵調(diào)用方法put()、get()以及put()涉及的已存在變量移位。
哇哦!看來要做的事情也并沒有這么多,那我們就先來看看第一次構(gòu)造出來的框架好了。
public class LruCache { private Object objects[]; private int maxSize; private int currentSize; public LruCache(int size){ objects = new Object[size]; maxSize = size; } /** * 插入item * @param item */ public void put(Object item){ } /** * 獲取item * @param item */ public Object get(Object item){ return null; } /** * 根據(jù)下標(biāo)對應(yīng),將后續(xù)數(shù)組移位 * @param index */ public void move(int index){ } }
因?yàn)橹灰菙?shù)組變換就存在移位,所以移位操作是必不可少的。那我們現(xiàn)在的工作也就是把數(shù)據(jù)填好了,對應(yīng)的移位是怎么樣的操作的思路了。
public class LruCache { public Object objects[]; private int maxSize; public int currentSize; public LruCache(int size) { objects = new Object[size]; maxSize = size; } /** * 插入item * * @param item */ public void put(Object item) { // 容量未滿時分成兩種情況 // 1。 容器內(nèi)存在 // 2。 容器內(nèi)不存在 int index = search(item); if (index == -1) { if (currentSize < maxSize) { //容器未滿,直接插入 objects[currentSize] = item; currentSize++; } else { // 容器已滿,刪去頭部插入 move(0); objects[currentSize - 1] = item; } }else { move(index); } } /** * 獲取item * * @param item */ public Object get(Object item) { int index = search(item); return index == -1 ? null : objects[index]; } /** * 根據(jù)下標(biāo)對應(yīng),將后續(xù)數(shù)組移位 * * @param index */ public void move(int index) { Object temp = objects[index]; // 將后續(xù)數(shù)組移位 for (int i = index; i < currentSize - 1; i++) { objects[i] = objects[i + 1]; } objects[currentSize - 1] = temp; } /** * 搜尋數(shù)組中的數(shù)組 * 存在則返回下標(biāo) * 不存在則返回 -1 * @param item * @return */ private int search(Object item) { for (int i = 0; i < currentSize; i++) { if (item.equals(objects[i])) return i; } return -1; }
因?yàn)橐呀?jīng)真的寫的比較詳細(xì)了,也沒什么難度的擼了我的20分鐘,希望讀者們能夠快入入門,下面給出我的一份測試樣例,結(jié)束這個話題。
“怎么使用Glide的LruCache”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!