LruCache缓存机制

LruCache缓存机制

基本使用:

// 设置lruCache缓存大小

    int maxLruCache= (int) (Runtime.getRuntime().maxMemory()/8);
    LruCache lruCache=new LruCache(maxLruCache){
        @Override
        protected int sizeOf(String key, Bitmap value) {
            return super.sizeOf(key, value);
        }
    };

}

定义:

A cache that holds strong references to a limited number of values. Each time

  • a value is accessed, it is moved to the head of a queue. When a value is
  • added to a full cache, the value at the end of that queue is evicted and may
  • become eligible for garbage collection.

用于保留限定数量的强引用缓存,每次值被访问,就会将值移动到队列的头部,当到达full缓存值,队列末尾的值将变为被垃圾回收的对象

1、构造方法

 public LruCache(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        this.maxSize = maxSize;
        this.map = new LinkedHashMap(0, 0.75f, true);
    }

通过LinkedHashMap对LruCache进行管理

2、resize方法

/**
* Sets the size of the cache.
*
* @param maxSize The new maximum size.
*/

public void resize(int maxSize) {
    if (maxSize <= 0) {
        throw new IllegalArgumentException("maxSize <= 0");
    }

    synchronized (this) {
        this.maxSize = maxSize;
    }
    trimToSize(maxSize);
}

可以通过resize对laruCache最大缓存值进行重新设定

3、get方法

/**
* Returns the value for {@code key} if it exists in the cache or can be
* created by {@code #create}. If a value was returned, it is moved to the
* head of the queue. This returns null if a value is not cached and cannot
* be created.
*/

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取出该值,调用put方法,将数据存在队列头部,再将该该值之前存储的位置从队列中移除,从而实现每次调用后将该值移到队列最顶端

4、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);
        if (previous != null) {
            size -= safeSizeOf(key, previous);
        }
    }

    if (previous != null) {
        entryRemoved(false, key, previous, value);
    }

    trimToSize(maxSize);
    return previous;
}

将键值对存储到cache中,如果之前存在该键对应的值,就把旧值移除,同时调整缓存对象,cache值超过最大值则依次删除排在最后的值,直到能够存下该对象为止

5、trimToSize(maxSize);

/**
* Remove the eldest entries until the total of remaining entries is at or
* below the requested size.
*
* @param maxSize the maximum size of the cache before returning. May be -1
* to evict even 0-sized elements.
*/

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) {
                break;
            }

            Map.Entry toEvict = map.eldest();
            if (toEvict == null) {
                break;
            }

            key = toEvict.getKey();
            value = toEvict.getValue();
            map.remove(key);
            size -= safeSizeOf(key, value);
            evictionCount++;
        }

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

6、remove方法 通过键移除该缓存对象

/**
* Removes the entry for {@code key} if it exists.
*
* @return the previous value mapped by {@code key}.
*/

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

    V previous;
    synchronized (this) {
        previous = map.remove(key);
        if (previous != null) {
            size -= safeSizeOf(key, previous);
        }
    }

    if (previous != null) {
        entryRemoved(false, key, previous, null);
    }

    return previous;
}

7、LinkedHashMap方法 get()

/**
* Returns the value to which the specified key is mapped,
* or {@code null} if this map contains no mapping for the key.
*
*

More formally, if this map contains a mapping from a key
* {@code k} to a value {@code v} such that {@code (keynull ? knull :
* key.equals(k))}, then this method returns {@code v}; otherwise
* it returns {@code null}. (There can be at most one such mapping.)
*
*

A return value of {@code null} does not necessarily
* indicate that the map contains no mapping for the key; it’s also
* possible that the map explicitly maps the key to {@code null}.
* The {@link #containsKey containsKey} operation may be used to
* distinguish these two cases.
*/

public V get(Object key) {
    Node e;
    if ((e = getNode(hash(key), key)) == null)
        return null;
    if (accessOrder)
        afterNodeAccess(e);
    return e.value;
}

void afterNodeAccess(Node e) {

// 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)   // p是头结点
            head = a;    // 改变节点位置移除p
        else
            b.after = a; // p不是头结点,将p的头结点与p的尾节点进行连接,移除p节点
        if (a != null)   // p 不是尾节点
            a.before = b; // 将p的头结点与p的尾节点进行连接,移除p节点
        else
            last = b;    // p是尾节点,直接将尾节点设置为p的头结点,移除p
        if (last == null) // 尾节点为空,证明只有一个元素
            head = p;     // 头结点和尾节点都是p
        else {
            p.before = last; // 有尾节点,将p的头结点作为尾节点,移除p
            last.after = p;  // 将p放在尾节点位置
        }
        tail = p;            // p作为尾节点,实现每次引用都将该元素放在链表的尾节点处
        ++modCount;          // 计数器累加元素
    }
}

通过LinkedHashMap的get方法实现调用后将数据添加到队列最末端,内存不足时移除链表最前端部分。

你可能感兴趣的:(android开发,源码分析)