Glide LruCache

LruCache

public class LruCache<K, V> {
    //hashmap初始容量100率寡,實際會初始化一個128長度的table
    //accessOrder:true,按訪問順序排序
    private final java.util.LinkedHashMap<K, V> cache =
            new LinkedHashMap<K, V>(100, 0.75f, true);
    //目前cache最大容量
    private int maxSize;
    //最開始的cache最大容量
    private final int initialMaxSize;
    //cache當前大小
    private int currentSize = 0;

    /**
     * @param size cache最大的size,單位應該和getSize(Object)放回得到的size的單位一致十气。比如字節(jié)捕捂。
     */
    public LruCache(int size) {
        this.initialMaxSize = size;
        this.maxSize = size;
    }

    /**
     * 設置一個乘數(shù)瑟枫,作用于size斗搞,如果一開始的時候我們設置的maxSize = 100,通過這個方法設置一個乘數(shù),
     * 比如設置的是2慷妙,那新的maxSize就是200僻焚,如果設置的乘數(shù)是0.5,那maxsize就是50
     * 如果計算出來的新的maxSize < currentSize膝擂,entries就執(zhí)行收縮虑啤,驅(qū)逐年齡最大的,直到當前的size <= 新的 maxSize
     */
    public void setSizeMultiplier(float multiplier) {
        if (multiplier < 0) {
            throw new IllegalArgumentException("Multiplier must be >= 0");
        }
        //計算一個新的maxSize
        maxSize = Math.round(initialMaxSize * multiplier);
        //試圖驅(qū)逐年齡最大的node
        evict();
    }

    /**
     * 返回緩存對象的item的size,默認這里設置的是1架馋,如果是bitmap狞山,需要子類重寫這個方法,然后計算item真正的size返回叉寂。
     * 計算的單位需要和構(gòu)造方法中的size匹配萍启,單位通常是字節(jié)。
     *
     * @param item 要計算緩存大小的對象屏鳍。
     */
    protected int getSize(V item) {
        return 1;
    }

    /**
     * 如果一個item從cache中被驅(qū)逐勘纯,這個回調(diào)方法需要在合適的時機被調(diào)用,默認是個空實現(xiàn)钓瞭,需要子類重寫驳遵。
     *
     * @param key 被驅(qū)逐的item的key.
     * @param item 被驅(qū)逐的item.
     */
    protected void onItemEvicted(K key, V item) {
        // optional override
    }

    public int getMaxSize() {
        return maxSize;
    }

    public int getCurrentSize() {
        return currentSize;
    }

    /**
     * 直接調(diào)用HashMap的方法,判斷與key相同的緩存單元是否存在山涡。
     */

    public boolean contains(K key) {
        return cache.containsKey(key);
    }

    /**
     * 根據(jù)key獲取item堤结,直接調(diào)用的是LinkedHashMap 的方法。
     *
     * @param key The key to check.
     */
    public V get(K key) {
        return cache.get(key);
    }

    /**
     * Adds the given item to the cache with the given key and returns any previous entry for the given key that may
     * have already been in the cache.
     *
     * 把一個item添加到緩存佳鳖,如果之前已經(jīng)有添加過相同的key的緩存霍殴,那hashmap默認其實會將value替換,返回返回之前的value系吩。
     * 所以這個方法的返回值就是那個替換下來的舊的value。如果key沒有添加過妒蔚,那么會返回null穿挨。
     *
     * 如果, 要添加的這個item的單個的緩存 > 整個緩存的maxSize。那就不能讓這個item添加成功肴盏,直接舍棄科盛,并且調(diào)用onItemEvicted回調(diào)。
     */
    public V put(K key, V item) {
        final int itemSize = getSize(item);
        if (itemSize >= maxSize) {
            onItemEvicted(key, item);
            return null;
        }

        final V result = cache.put(key, item);
        if (item != null) {
            currentSize += getSize(item);
        }
        if (result != null) {
            // TODO: should we call onItemEvicted here?
            currentSize -= getSize(result);
        }
        evict();

        return result;
    }

    /**
     * 刪除
     */
    public V remove(K key) {
        //根據(jù)key刪除value
        final V value = cache.remove(key);
        if (value != null) {
            //如果value占據(jù)著緩存容量菜皂,從currentSize中減掉item的緩存size贞绵。
            currentSize -= getSize(value);
        }
        return value;
    }

    /**
     * 清空
     */
    public void clearMemory() {
        trimToSize(0);
    }

    /**
     * 如果currentSize > size, 清除緩存中哪些年齡最大的緩存單元,直到cache滿足currentSize <= size
     */
    protected void trimToSize(int size) {
        Map.Entry<K, V> last;
        while (currentSize > size) {
            //從表頭取數(shù)據(jù)
            last = cache.entrySet().iterator().next();
            //獲取緩存數(shù)據(jù)
            final V toRemove = last.getValue();
            //計算這個緩存item的size恍飘,并計算當前currentSize
            currentSize -= getSize(toRemove);
            //得到這個item的key
            final K key = last.getKey();
            //從緩存總刪除
            cache.remove(key);
            //調(diào)用callBack
            onItemEvicted(key, toRemove);
        }
    }

    //驅(qū)逐年齡大的緩存單元榨崩。直到maxSize
    private void evict() {
        trimToSize(maxSize);
    }
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谴垫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子母蛛,更是在濱河造成了極大的恐慌翩剪,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件彩郊,死亡現(xiàn)場離奇詭異前弯,居然都是意外死亡,警方通過查閱死者的電腦和手機秫逝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門恕出,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人违帆,你說我怎么就攤上這事剃根。” “怎么了前方?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵狈醉,是天一觀的道長。 經(jīng)常有香客問我惠险,道長苗傅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任班巩,我火速辦了婚禮渣慕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘抱慌。我一直安慰自己逊桦,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布抑进。 她就那樣靜靜地躺著强经,像睡著了一般。 火紅的嫁衣襯著肌膚如雪寺渗。 梳的紋絲不亂的頭發(fā)上匿情,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音信殊,去河邊找鬼炬称。 笑死,一個胖子當著我的面吹牛涡拘,可吹牛的內(nèi)容都是我干的玲躯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼跷车!你這毒婦竟也來了棘利?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤姓赤,失蹤者是張志新(化名)和其女友劉穎赡译,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體不铆,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡蝌焚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了誓斥。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片只洒。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖劳坑,靈堂內(nèi)的尸體忽然破棺而出毕谴,到底是詐尸還是另有隱情,我是刑警寧澤距芬,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布涝开,位于F島的核電站,受9級特大地震影響框仔,放射性物質(zhì)發(fā)生泄漏舀武。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一离斩、第九天 我趴在偏房一處隱蔽的房頂上張望银舱。 院中可真熱鬧,春花似錦跛梗、人聲如沸寻馏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诚欠。三九已至,卻和暖如春宪祥,著一層夾襖步出監(jiān)牢的瞬間聂薪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工蝗羊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人仁锯。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓耀找,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子野芒,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容