android开发LruCache原理理解与源码实现方式

  • LRU原理:

    • 简写:Least Recently Used
    • 即最近最少使用,是一种调度算法或者说淘汰机制。就是每个Item都有一个访问字段t,记录自上次被访问的时间,当需要移除时选择移除t值最大的Item。
  • androidx.collection.LruCache实现

    • 基层依赖LinkedHashMap。而LinkedHashMap是一个双向链表。
    public LruCache(int maxSize) {//最大缓存大小
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        this.maxSize = maxSize;
        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
    }
    //accessOrder为false,表示map元素顺序跟随插入顺序,默认值。
    //accessOrder为true,表示map元素顺序跟随访问顺序变化。即一个元素被访问时,同时调整其位置将其放到最后,刚好符合lru原则。
    
    • put方法
    public final V put(@NonNull K key, @NonNull V value) {
        V previous;
        synchronized (this) {//线程安全的
            size += safeSizeOf(key, value);
            //在key位置上放新值value,返回key位置之前的旧值
            previous = map.put(key, value);
            if (previous != null) {//减去旧值的size
                size -= safeSizeOf(key, previous);
            }
        }
        //如果旧值不为空,则回调entryRemoved方法
        if (previous != null) {
            entryRemoved(false, key, previous, value);
        }
        trimToSize(maxSize);//size变化了,检查要不要剔除最老元素
        return previous;
    }
    
    • get方法
    public final V get(@NonNull K key) {
        V mapValue;
        synchronized (this) {
        //注意:get方法不仅取值,如果取到了还会更新该元素位置
        //即移到链表最后位置tail,因为之前参数accessOrder为true
            mapValue = map.get(key);
            if (mapValue != null) {
                return mapValue;//找到了直接返回
            }
        }
        V createdValue = create(key);//找不到就创建新的
        if (createdValue == null) {
            return null;
        }
        synchronized (this) {
            mapValue = map.put(key, createdValue);
            if (mapValue != null) {//基本为null,除非并发
                map.put(key, mapValue);
            } else {//size变化,后面调用trimToSize重新检查调整
                size += safeSizeOf(key, createdValue);
            }
        }
        if (mapValue != null) {//并发导致刚好已经有旧值了
            entryRemoved(false, key, createdValue, mapValue);
            return mapValue;
        } else {
            trimToSize(maxSize);
            return createdValue;
        }
    }
    
    • trimToSize方法
    public void trimToSize(int maxSize) {
        while (true) {
            K key;
            V value;
            synchronized (this) {
                //如果size没有达到最大缓存maxSize或者map为空,直接返回了,不需要移除操作
                if (size <= maxSize || map.isEmpty()) {
                    break;
                }
                //获取第一个元素,也就是最老最久没被使用的元素,将它移除。还记得get时会刷新get到元素的位置吧??
                Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
                key = toEvict.getKey();
                value = toEvict.getValue();
                map.remove(key);
                size -= safeSizeOf(key, value);//移除后size减少
            }
            entryRemoved(true, key, value, null);
        }
    }
    
posted @ 2020-07-13 15:51  yongfengnice  阅读(709)  评论(0编辑  收藏  举报