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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM