杂谈(Lrucache机制)

杂谈(app优化、android机制系列)
杂谈(Lrucache机制)
杂谈(android基础知识点梳理笔记)
杂谈(http / https Socket)
简介

LruCache是Android 3.1所提供的一个缓存类,目前主流的图片加载框架底层大部分都是基于它。
LruCache内部维护了一个LinkedHashMap,利用LinkedHashMap的数据结构特点去实现最近很少使用这一算法进行缓存。

LinkedHashMap介绍

LinkedHashMap的数据结构:散列表+双向链表

特点:双向链表结构可以控制访问顺序和插入顺序,使得LinkedHashMap中的<key,value>对按照一定顺序排列起来。


   public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

accessOrder:true 则为访问顺序,为false,则为插入顺序

LruCache
public LruCache(int maxSize) {
   // ......省略N行代码
   
    // 由此可见内部维护的是一个LinkedHashMap
    this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
put
    public final V put(K key, V value) {
         // ......省略N行代码
        synchronized (this) {
            putCount++;
           // safeSizeOf 计算缓存大小
            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;
    }
  1. safeSizeOf
// 计算缓存大小
 private int safeSizeOf(K key, V value) {
        int result = sizeOf(key, value);
        if (result < 0) {
            throw new IllegalStateException("Negative size: " + key + "=" + value);
        }
        return result;
    }
  1. entryRemoved
//当item被回收或者删掉时调用。改方法当value被回收释放存储空间时被remove调用,
//或者替换item值时put调用,默认实现什么都没做
//evicted true---为释放空间被删除;false---put或remove导致
            
    protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}

  1. sizeOf 方法是我们要重写的
protected int sizeOf(K key, V value) {
        return 1;
    }
  1. trimToSize
    一个死循环,不断地删除LinkedHashMap中队尾的元素,即近期最少访问的,直到缓存大小小于最大值。
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.eldest(); 返回映射中最老的条目,如果映射为空,则返回null
                Map.Entry<K, V> 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);
        }
    }

get

调用一次get就相当于访问了一次该元素,将会更新队列,保持整个队列是按照访问顺序排序。这个更新过程就是在LinkedHashMap中的get()方法中完成的。

 public final V get(K key) {
        if (key == null) {
            throw new NullPointerException("key == null");
        }
        V mapValue;
        synchronized (this) {
            //获取对应的缓存对象
            //get()方法会实现将访问的元素更新到队列头部的功能
            mapValue = map.get(key);
            if (mapValue != null) {
                hitCount++;
                return mapValue;
            }
            missCount++;
        }

      // ......省略N行代码
    }
remove

从缓存中去删除内容,并更新已经缓存的大小

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;
    }

总结:

  1. LruCache中维护了一个集合LinkedHashMap。
  2. LinkedHashMap是以访问顺序排序的(accessOrder=true)
  3. 当调用put()方法时,就会在集合中添加元素(safeSizeOf来计算缓存大小)
  4. put时最后调用trimToSize()(内部一个死循环): 判断缓存是否已满,如果满了就用LinkedHashMap的eldest(),返回一个最老元素
  5. 当调用get()方法访问缓存对象时,就会调用LinkedHashMap的get()方法获得对应集合元素,同时会更新该元素到队头。
  6. 我们需要重新sizeOf ,entryRemoved也可以重写。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值