android lru緩存 輔助類LruCache源碼解析

android lru緩存 輔助類LruCache 使用和解析

LruCache 緩存到底是什麼,LRU是Least Recently Used 的縮寫,翻譯過來就是“最近最少使用”,LRU緩存就是使用這種原理實現,簡單的說就是緩存一定量的數據,當超過設定的閾值時就把一些過期的數據刪除掉,比如我們緩存100M的數據,當總數據小於100M時可以隨意添加,當超過100M時就需要把新的數據添加進來,同時要把過期數據刪除,以確保我們最大緩存100M。 聽瞭lrucache的作用,是不是很適合作為一種內存管理的方法呢


構造方法

 /**
     * @param maxSize for caches that do not override {@link #sizeOf}, this is
     *     the maximum number of entries in the cache. For all other caches,
     *     this is the maximum sum of the sizes of the entries in this cache.
     */
    public LruCache(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        this.maxSize = maxSize;
        this.map = new LinkedHashMap(0, 0.75f, true);
    }

可以看到構造方法中設置瞭最大的size同時創建瞭一個LinkedHashMap。

put方法

/**
     * Caches {@code value} for {@code key}. The value is moved to the head of
     * the queue.
     *
     * @return the previous value mapped by {@code key}.
     */
    public final V put(K key, V value) {
        if (key == null || value == null) {
            throw new NullPointerException("key == null || value == null");
        }

        V previous;
        synchronized (this) {
            putCount++;
            size += safeSizeOf(key, value);   //加上長度
            previous = map.put(key, value);   //如果已經存在返回v
            if (previous != null) {           //如果已經存在減掉已經加上的長度
                size -= safeSizeOf(key, previous);
            }
        }

        if (previous != null) {             // 方法通知舊數據被更新為新的值
            entryRemoved(false, key, previous, value);
        }

        trimToSize(maxSize);               
        return previous;
    }

get方法

public final V get(K key) {
        if (key == null) {
            throw new NullPointerException("key == null");
        }

        V mapValue;
        synchronized (this) {
            mapValue = map.get(key);
            if (mapValue != null) {
                hitCount++;
                return mapValue;
            }
            missCount++;
        }

        /*
         * Attempt to create a value. This may take a long time, and the map
         * may be different when create() returns. If a conflicting value was
         * added to the map while create() was working, we leave that value in
         * the map and release the created value.
         */

        V createdValue = create(key);
        if (createdValue == null) {
            return null;
        }

        synchronized (this) {
            createCount++;
            mapValue = map.put(key, createdValue);

            if (mapValue != null) {
                // There was a conflict so undo that last put
                map.put(key, mapValue);
            } else {
                size += safeSizeOf(key, createdValue);
            }
        }

        if (mapValue != null) {
            entryRemoved(false, key, createdValue, mapValue);
            return mapValue;
        } else {
            trimToSize(maxSize);
            return createdValue;
        }
    }

可以看到get方法傳入瞭key進行查找,如果找到就返回,同時默認返回空的creat方法,當creat被重寫後,creat可能會耗時,同時createdValue可能會改變,同時可能會有put方法將新的同樣的key的方法添加進去,所以後面會看到和put方法一樣的操作。

trimToSize方法

public void trimToSize(int maxSize) {
        while (true) {
            K key;
            V value;
            synchronized (this) {
                if (size < 0 || (map.isEmpty() && size != 0)) {
                    throw new IllegalStateException(getClass().getName()
                            + ".sizeOf() is reporting inconsistent results!");
                }

                if (size <= maxSize || map.isEmpty()) {
                    break;
                }

                Map.Entry toEvict = map.entrySet().iterator().next();
                key = toEvict.getKey();
                value = toEvict.getValue();
                map.remove(key);
                size -= safeSizeOf(key, value);
                evictionCount++;
            }

            entryRemoved(true, key, value, null);
        }
    }

同時trimToSize方法將會對溢出情況進行判斷,移除最少使用的部分。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *