Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android常見的內存緩存算法

Android常見的內存緩存算法

編輯:關於Android編程

本片博客主要簡介以下Android兩個問題

介紹一下常見的內存緩存算法 怎樣實現這些Android算法

大家應該對ImageLoader這個框架都不陌生吧,一個很強大的圖片加載框架,雖然作者去年的時候已經停止維護了,但裡面的許多東西還是值得我們去學習的。本篇博客講解的內存緩存算法正是基於ImageLoader的實現基礎之上的

常見的幾種緩存算法

(1)LRU即Least RecentlyUsed,近期最少使用算法。

也就是當內存緩存達到設定的最大值時將內存緩存中近期最少使用的對象移除,有效的避免了OOM的出現。

(2)Least Frequently Used(LFU)

對每個緩存對象計算他們被使用的頻率。把最不常用的緩存對象換走。

(3)、First in First out(FIFO)

這是一個低負載的算法,並且對緩存對象的管理要求不高。通過一個隊列去跟蹤所有的緩存對象,最近最常用的緩存對象放在後面,而更早的緩存對象放在前面,當緩存容量滿時,排在前面的緩存對象會被踢走,然後把新的緩存對象加進去。

(4)、Simple time-based

通過絕對的時間周期去失效那些緩存對象。對於新增的對象,保存特定的時間。

(5)、LargestLimitedMemoryCache

超過指定緩存的話,每次移除棧最大內存的緩存的對象

下面我們一起來看一下ImageLoader是怎樣實現這些算法的

首先我們一起先來看一下類UML圖

\

源碼分析

1)首先我們先來看一下BaseMemoryCache做了什麼?
public abstract class BaseMemoryCache implements MemoryCache {

    /** Stores not strong references to objects */
    private final Map> softMap = Collections.synchronizedMap(new HashMap>());

    @Override
    public Bitmap get(String key) {
        Bitmap result = null;
        Reference reference = softMap.get(key);
        if (reference != null) {
            result = reference.get();
        }
        return result;
    }

    @Override
    public boolean put(String key, Bitmap value) {
        softMap.put(key, createReference(value));
        return true;
    }

    @Override
    public Bitmap remove(String key) {
        Reference bmpRef = softMap.remove(key);
        return bmpRef == null ? null : bmpRef.get();
    }

    @Override
    public Collection keys() {
        synchronized (softMap) {
            return new HashSet(softMap.keySet());
        }
    }

    @Override
    public void clear() {
        softMap.clear();
    }

    /** Creates {@linkplain Reference not strong} reference of value */
    protected abstract Reference createReference(Bitmap value);
}

其實就是保存著一份弱引用而已,而它的父類Memory只是定義了幾個接口方法,統一標准而已

2)接著我們來看LimitedMemoryCache做了什麼?
public abstract class LimitedMemoryCache extends BaseMemoryCache {

    private static final int MAX_NORMAL_CACHE_SIZE_IN_MB = 16;
    private static final int MAX_NORMAL_CACHE_SIZE = MAX_NORMAL_CACHE_SIZE_IN_MB * 1024 * 1024;

    private final int sizeLimit;

    private final AtomicInteger cacheSize;

    /**
     * Contains strong references to stored objects. Each next object is added last. If hard cache size will exceed
     * limit then first object is deleted (but it continue exist at {@link #softMap} and can be collected by GC at any
     * time)
     */
    private final List hardCache = Collections.synchronizedList(
                                                         new LinkedList());

    /** @param sizeLimit Maximum size for cache (in bytes) */
    public LimitedMemoryCache(int sizeLimit) {
        this.sizeLimit = sizeLimit;
        cacheSize = new AtomicInteger();
        if (sizeLimit > MAX_NORMAL_CACHE_SIZE) {
            L.w("You set too large memory cache size (more than %1$d Mb)", 
                                                         MAX_NORMAL_CACHE_SIZE_IN_MB);
        }
    }

    @Override
    public boolean put(String key, Bitmap value) {
        boolean putSuccessfully = false;
        // Try to add value to hard cache
        int valueSize = getSize(value);
        int sizeLimit = getSizeLimit();
        int curCacheSize = cacheSize.get();
        if (valueSize < sizeLimit) {
            while (curCacheSize + valueSize > sizeLimit) {
                Bitmap removedValue = removeNext();
                if (hardCache.remove(removedValue)) {
                    curCacheSize = cacheSize.addAndGet(-getSize(removedValue));
                }
            }
            hardCache.add(value);
            cacheSize.addAndGet(valueSize);

            putSuccessfully = true;
        }
        // Add value to soft cache
        super.put(key, value);
        return putSuccessfully;
    }

    @Override
    public Bitmap remove(String key) {
        Bitmap value = super.get(key);
        if (value != null) {
            if (hardCache.remove(value)) {
                cacheSize.addAndGet(-getSize(value));
            }
        }
        return super.remove(key);
    }

    @Override
    public void clear() {
        hardCache.clear();
        cacheSize.set(0);
        super.clear();
    }

    protected int getSizeLimit() {
        return sizeLimit;
    }

    protected abstract int getSize(Bitmap value);

    protected abstract Bitmap removeNext();
}

LimitedMemoryCache所做的工作可以分為以下幾步

1) 保存著一份強引用
private final List hardCache = Collections.synchronizedList(
new LinkedList());

2) 其實在我們調用put方法的時候,即我們把bitmap存進內存的時候,他會判斷是否超出我們的最大值,超出我們的最大值就會調用removeNext();來獲得我們將要移除的bitmap對象,最終再調用hardCache.remove(removedValue)去移除它。

3) 注意到removeNext()方法是抽象方法,交給子類自己去實現自己的算法邏輯。

注意事項

結合BaseMemoryCache和LimitedMemoryCache,我們可以知道LimitedMemoryCache的子類,至少保存著兩份引用,一份是強引用,一份是弱引用

//父類BaseMemoryCache的成員變量,並且每次在操作的時候都會把bitmap的弱引用存進去
 private final Map> softMap = Collections.synchronizedMap(
                new HashMap>());

//LimitedMemoryCache的成員變量,緩存的bitmap是強引用
private final List hardCache = Collections.synchronizedList(new LinkedList());                

有人可能會有疑問了這些成員變量不是私有的嗎?為什麼說LimitedMemoryCache的子類,至少保存著兩份引用,這點我們可以從他們的put方法中知道

@Override
public boolean put(String key, Bitmap value) {
   boolean putSuccessfully = false;
   // Try to add value to hard cache
   int valueSize = getSize(value);
   int sizeLimit = getSizeLimit();
   int curCacheSize = cacheSize.get();
   if (valueSize < sizeLimit) {
      while (curCacheSize + valueSize > sizeLimit) {
         Bitmap removedValue = removeNext();
         if (hardCache.remove(removedValue)) {
            curCacheSize = cacheSize.addAndGet(-getSize(removedValue));
         }
      }
      hardCache.add(value);
      cacheSize.addAndGet(valueSize);

      putSuccessfully = true;
   }
   // Add value to soft cache
   super.put(key, value);
   return putSuccessfully;
}

同理LimitedMemoryCache的子類put也會調用LimitedMemoryCache的put方法,代碼見下面分析。

同時從上面的分析當中我們可以知道主要關心put和removeNext()這兩個方法就可以了,put()方法其實就是把bitmap對象存進我們的queue隊列中

下面我們在看一下UsingFreqLimitedMemoryCache是怎樣實現的?

public class UsingFreqLimitedMemoryCache extends LimitedMemoryCache {
    /**
     * Contains strong references to stored objects (keys) and last object usage date (in milliseconds). If hard cache
     * size will exceed limit then object with the least frequently usage is deleted (but it continue exist at
     * {@link #softMap} and can be collected by GC at any time)
     */
    private final Map usingCounts = Collections.synchronizedMap(new HashMap());

    public UsingFreqLimitedMemoryCache(int sizeLimit) {
        super(sizeLimit);
    }

    @Override
    public boolean put(String key, Bitmap value) {
        if (super.put(key, value)) {
            usingCounts.put(value, 0);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Bitmap get(String key) {
        Bitmap value = super.get(key);
        // Increment usage count for value if value is contained in hardCahe
        if (value != null) {
            Integer usageCount = usingCounts.get(value);
            if (usageCount != null) {
                usingCounts.put(value, usageCount + 1);
            }
        }
        return value;
    }

    @Override
    public Bitmap remove(String key) {
        Bitmap value = super.get(key);
        if (value != null) {
            usingCounts.remove(value);
        }
        return super.remove(key);
    }

    @Override
    public void clear() {
        usingCounts.clear();
        super.clear();
    }

    @Override
    protected int getSize(Bitmap value) {
        return value.getRowBytes() * value.getHeight();
    }

    @Override
    protected Bitmap removeNext() {
        Integer minUsageCount = null;
        Bitmap leastUsedValue = null;
        Set> entries = usingCounts.entrySet();
        synchronized (usingCounts) {
            for (Entry entry : entries) {
                if (leastUsedValue == null) {
                    leastUsedValue = entry.getKey();
                    minUsageCount = entry.getValue();
                } else {
                    Integer lastValueUsage = entry.getValue();
                    if (lastValueUsage < minUsageCount) {
                        minUsageCount = lastValueUsage;
                        leastUsedValue = entry.getKey();
                    }
                }
            }
        }
        usingCounts.remove(leastUsedValue);
        return leastUsedValue;
    }

    @Override
    protected Reference createReference(Bitmap value) {
        return new WeakReference(value);
    }
}

思路解析

當我們調用put方法,把bitmap存進內存的時候,他會判斷是否超出我們的最大值,超出我們的最大值就會調用removeNext();來獲得我們將要移除的bitmap對象,最終再調用hardCache.remove(removedValue)去移除它。

@Override
public boolean put(String key, Bitmap value) {
boolean putSuccessfully = false;
// Try to add value to hard cache
int valueSize = getSize(value);
int sizeLimit = getSizeLimit();
int curCacheSize = cacheSize.get();
if (valueSize < sizeLimit) {
  while (curCacheSize + valueSize > sizeLimit) {
     Bitmap removedValue = removeNext();
     if (hardCache.remove(removedValue)) {
        curCacheSize = cacheSize.addAndGet(-getSize(removedValue));
     }
  }
  hardCache.add(value);
  cacheSize.addAndGet(valueSize);

  putSuccessfully = true;
}
// Add value to soft cache
super.put(key, value);
return putSuccessfully;
}

···

* 下面我們來看一下removeNext()是怎樣獲得將要移除的bitmap對象的?

```java
private final Map usingCounts = Collections.
                         synchronizedMap(new HashMap());


@Override
protected Bitmap removeNext() {
Integer minUsageCount = null;
Bitmap leastUsedValue = null;
Set> entries = usingCounts.entrySet();
synchronized (usingCounts) {
  for (Entry entry : entries) {
     if (leastUsedValue == null) {
        leastUsedValue = entry.getKey();
        minUsageCount = entry.getValue();
     } else {
        Integer lastValueUsage = entry.getValue();
        if (lastValueUsage < minUsageCount) {
           minUsageCount = lastValueUsage;
           leastUsedValue = entry.getKey();
        }
     }
  }
}
usingCounts.remove(leastUsedValue);
return leastUsedValue;
}

其實就是將usingCounts中出現次數最少的節點移除掉。

那它實在什麼時候計算bitmap的使用次數的呢?相信大多數人會想到,既然是使用頻率,那肯定是在取圖片的過程中計算的,沒錯,下面讓我們一起來看一下是怎樣實現的?

@Override
public Bitmap get(String key) {
Bitmap value = super.get(key);
// Increment usage count for value if value is contained in hardCahe
if (value != null) {
  Integer usageCount = usingCounts.get(value);
  if (usageCount != null) {
     usingCounts.put(value, usageCount + 1);
  }
}
return value;
}

其實也很簡單,判斷是否存在緩存value,存在的話,使用次數加一

好的,到此UsingFreqLimitedMemoryCache的源碼分析位置


FIFOLimitedMemoryCache源碼分析

public class FIFOLimitedMemoryCache extends LimitedMemoryCache {

    private final List queue = Collections.synchronizedList(new LinkedList());

    public FIFOLimitedMemoryCache(int sizeLimit) {
        super(sizeLimit);
    }

    @Override
    public boolean put(String key, Bitmap value) {
        if (super.put(key, value)) {
            queue.add(value);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Bitmap remove(String key) {
        Bitmap value = super.get(key);
        if (value != null) {
            queue.remove(value);
        }
        return super.remove(key);
    }

    @Override
    public void clear() {
        queue.clear();
        super.clear();
    }

    @Override
    protected int getSize(Bitmap value) {
        return value.getRowBytes() * value.getHeight();
    }

    @Override
    protected Bitmap removeNext() {
        return queue.remove(0);
    }

    @Override
    protected Reference createReference(Bitmap value) {
        return new WeakReference(value);
    }
}
1)從上面的分析當中我們可以知道主要關心put和removeNext()這兩個方法就可以了,put()方法其實就是把bitmap對象存進我們的queue隊列中

2)remove方法其實就是一出隊列的第一個bitmap對象,將先進先出,符合我們的FIFO原則

@Override
public Bitmap get(String key) {
Bitmap result = null;
Reference reference = softMap.get(key);
if (reference != null) {
  result = reference.get();
}
return result;
}

LargestLimitedMemoryCache源碼分析

public class LargestLimitedMemoryCache extends LimitedMemoryCache {
    /**
     * Contains strong references to stored objects (keys) and sizes of the objects. If hard cache
     * size will exceed limit then object with the largest size is deleted (but it continue exist at
     * {@link #softMap} and can be collected by GC at any time)
     */
    private final Map valueSizes = Collections.synchronizedMap(new HashMap());

    public LargestLimitedMemoryCache(int sizeLimit) {
        super(sizeLimit);
    }

    @Override
    public boolean put(String key, Bitmap value) {
        if (super.put(key, value)) {
            valueSizes.put(value, getSize(value));
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Bitmap remove(String key) {
        Bitmap value = super.get(key);
        if (value != null) {
            valueSizes.remove(value);
        }
        return super.remove(key);
    }


 //這裡我們省略若干個方法,有興趣的話講源碼去,下面有提供源碼下載地址
    @Override
    protected Bitmap removeNext() {
        Integer maxSize = null;
        Bitmap largestValue = null;
        Set> entries = valueSizes.entrySet();
        synchronized (valueSizes) {
            for (Entry entry : entries) {
                if (largestValue == null) {
                    largestValue = entry.getKey();
                    maxSize = entry.getValue();
                } else {
                    Integer size = entry.getValue();
                    if (size > maxSize) {
                        maxSize = size;
                        largestValue = entry.getKey();
                    }
                }
            }
        }
        valueSizes.remove(largestValue);
        return largestValue;
    }

}

同樣我們只關心put方法和removeNext()方法

@Override
public boolean put(String key, Bitmap value) {
    if (super.put(key, value)) {
         valueSizes.put(value, getSize(value));
         return true;
    }else {
         return false;
    }
}

@Override
protected Bitmap removeNext() {
   Integer maxSize = null;
   Bitmap largestValue = null;
   Set> entries = valueSizes.entrySet();
   synchronized (valueSizes) {
      for (Entry entry : entries) {
         if (largestValue == null) {
            largestValue = entry.getKey();
            maxSize = entry.getValue();
         } else {
            Integer size = entry.getValue();
            if (size > maxSize) {
               maxSize = size;
               largestValue = entry.getKey();
            }
         }
      }
   }
   valueSizes.remove(largestValue);
   return largestValue;
}

1)其實就是put方法的時候( valueSizes.put(value, getSize(value));),我們將bitmap做為key,大小作為value,存進valueSizesM集合 2)在超過最大緩存數量的時候,遍歷移除掉valueSizes中最大的bitmap。

下面我們來看一下LruMemoryCache是怎樣實現的

源碼我們就不貼出來了
主要邏輯在put方法中

// 存儲bitmap對象,在構造方法裡面初始化
private final LinkedHashMap map;


/** Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue. */
@Override
public final boolean put(String key, Bitmap value) {
   if (key == null || value == null) {
      throw new NullPointerException("key == null || value == null");
   }

   synchronized (this) {
      size += sizeOf(key, value);
      Bitmap previous = map.put(key, value);
      if (previous != null) {
         size -= sizeOf(key, previous);
      }
   }

   trimToSize(maxSize);
   return true;
}

當我們把bitmap存進內存的時候,他會trimToSize(maxSize)這個方法去判斷我們是否超過我們規定內存的最大值,超過的話移除掉最先添加進來的那個

private void trimToSize(int maxSize) {
   while (true) {
      String key;
      Bitmap 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();
         if (toEvict == null) {
            break;
         }
         key = toEvict.getKey();
         value = toEvict.getValue();
         map.remove(key);
         size -= sizeOf(key, value);
      }
   }
}
/**
 * Decorator for {@link MemoryCache}. Provides special feature for cache: if some cached object age exceeds defined
 * value then this object will be removed from cache.
 *
 * 采用裝飾著模式,計算對象的最大存活時間
 * 在get方法的時候判斷大於的移除掉
 *
 */
public class LimitedAgeMemoryCache implements MemoryCache {

    private final MemoryCache cache;

    private final long maxAge;
    private final Map loadingDates = Collections.synchronizedMap(new HashMap());

    /**
     * @param cache  Wrapped memory cache
     * @param maxAge Max object age (in seconds). If object age will exceed this value then it'll be removed from
     *               cache on next treatment (and therefore be reloaded).
     */
    public LimitedAgeMemoryCache(MemoryCache cache, long maxAge) {
        this.cache = cache;
        this.maxAge = maxAge * 1000; // to milliseconds
    }

    @Override
    public boolean put(String key, Bitmap value) {
        boolean putSuccesfully = cache.put(key, value);
        if (putSuccesfully) {
            loadingDates.put(key, System.currentTimeMillis());
        }
        return putSuccesfully;
    }

    @Override
    public Bitmap get(String key) {
        Long loadingDate = loadingDates.get(key);
        if (loadingDate != null && System.currentTimeMillis() - loadingDate > maxAge) {
            cache.remove(key);
            loadingDates.remove(key);
        }

        return cache.get(key);
    }

    @Override
    public Bitmap remove(String key) {
        loadingDates.remove(key);
        return cache.remove(key);
    }

    @Override
    public Collection keys() {
        return cache.keys();
    }

    @Override
    public void clear() {
        cache.clear();
        loadingDates.clear();
    }
}

分析

1)這個采用了裝飾者模式,包裝我們的Memory對象,不了解裝飾者模式的,建議先讀我的這一篇博客裝飾者模式及其應用:http://blog.csdn.net/gdutxiaoxu/article/details/51885105

2)主要邏輯在get方法裡面,在我們通過key取bitmap的時候,他會先判斷存活時間是否超出我們規定的maxAge(System.currentTimeMillis() - loadingDate > maxAge),超過的話移除掉

3)那我們是怎樣保存這些的存活時間的呢,其實很簡單?就是用一個loadingDates集合來保存,在我們put的時候,把當前的時間存進去,源碼體現如下
//成員變量,保持存活時間的map集合
private final Map loadingDates = Collections.synchronizedMap(
                                                      new HashMap());

@Override
public boolean put(String key, Bitmap value) {
   boolean putSuccesfully = cache.put(key, value);
   if (putSuccesfully) {
      loadingDates.put(key, System.currentTimeMillis());
   }
   return putSuccesfully;
}

感覺ImageLoader在實現FIFOLimitedMemoryCache算法的時候還是有一點缺陷,為什麼呢?

1)我們看了FIFOLimitedMemoryCache,LimitedMemoryCache,裡面的方法發現並沒沒有重寫get方法,只有BaseMemoryCache類有實現get方法,那這樣就會導致其實我們去緩存bitmap的時候,都會從softMap裡面去取,並沒有從我們的隊列裡面去取,我們知道,當內存緊張的時候,會有限回收弱引用引用的對象,有可能發生這樣的情況,弱引用用已經被回收了,但是我們的queue裡面的強引用還沒有回收。再者內存中同時保存著弱引用和強引用,相對來說也是比較占內存的(有錯誤的話歡迎指出) 2)個人感覺沒有必要使用雙引用了,弱應用和強引用,使用其中的一種就可以了,當然ImageLoader的LruCache實現就內存當中bitmap的緩存只保存著一份引用。

到此ImageLoader內存的緩存算法源碼分析為止,下面我稍微改一下實現方式,內存裡面不再保存著兩份引用了,bitmap的緩存只保存著一份引用。


自己實現的內存緩存算法

類UML圖
\

其實跟ImageLoader實現的也沒有多大區別,只是我去除了弱引用,每個實現類裡面不像LimitedMemZ喎?/kf/ware/vc/" target="_blank" class="keylink">vcnlDYWNoZbXEyrXP1sDg0rvR+bPW09DBvbfd0v3Tw7b40tE8L3A+DQo8aDMgaWQ9"首先我們來看一下limitedmemorycache是怎樣實現的">首先我們來看一下LimitedMemoryCache是怎樣實現的

public abstract class LimitedMemoryCache implements MemoryCache {

    private static final int MAX_NORMAL_CACHE_SIZE_IN_MB = 16;
    private static final int MAX_NORMAL_CACHE_SIZE = MAX_NORMAL_CACHE_SIZE_IN_MB * 1024 * 1024;

    private final int sizeLimit;
     public static final String TAG="tag";

    private final AtomicInteger cacheSize;

    private final Map mMap= Collections.synchronizedMap(new LinkedHashMap());



    public LimitedMemoryCache(int sizeLimit) {
        this.sizeLimit = sizeLimit;

        cacheSize = new AtomicInteger();
        if (sizeLimit > MAX_NORMAL_CACHE_SIZE) {
            Log.w(TAG,"You set too large memory cache size (more than %1$d Mb)"+ MAX_NORMAL_CACHE_SIZE_IN_MB);
        }

    }

    @Override
    public boolean put(String key, Bitmap value) {
        boolean putSuccessfully = false;
        // Try to add value to hard cache
        int valueSize = getSize(value);
        int sizeLimit = getSizeLimit();
        int curCacheSize = cacheSize.get();
        if (valueSize < sizeLimit) {
            while (curCacheSize + valueSize > sizeLimit) {
                String removeKey = removeNext();
                if(removeKey==null){
                   break;
                }
                Bitmap bitmap = mMap.remove(key);
                if(bitmap!=null){
                    curCacheSize = cacheSize.addAndGet(-getSize(bitmap));
                }
            }
            mMap.put(key,value);
            cacheSize.addAndGet(valueSize);
            putSuccessfully = true;
        }

        return putSuccessfully;
    }

    @Override
    public Bitmap remove(String key) {
        return  mMap.remove(key);
    }

    @Override
    public Bitmap get(String key) {
        return mMap.get(key);
    }

    @Override
    public void clear() {
        mMap.clear();
        cacheSize.set(0);
    }

    protected int getSizeLimit() {
        return sizeLimit;
    }

    @Override
    public Collection keys() {
        synchronized (mMap) {
            return new HashSet(mMap.keySet());
        }
    }

    protected abstract int getSize(Bitmap value);

    protected abstract String removeNext();
}

LimitedMemoryCache所做的工作可以分為以下幾步

1) 保存著一份強引用
//在構造方法裡面初始化      
private final Map mMap;
2) 在我們調用put方法的時候,即我們把bitmap存進內存的時候,他會判斷是否超出我們的最大值,超出我們的最大值就會調用removeNext();來獲得我們將要移除的bitmap對象,最終再調用hardCache.remove(removedValue)去移除它。 3) 注意到removeNext()方法是抽象方法,交給子類自己去實現自己的算法邏輯,返回類型是String。

下面我們來看一下

public class UsingFreqLimitedMemoryCache extends LimitedMemoryCache {

    private final Map usingCounts = Collections.synchronizedMap(new HashMap());

//這裡省略了若干個方法
    @Override
    public boolean put(String key, Bitmap value) {
        if (super.put(key, value)) {
            usingCounts.put(key, 0);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Bitmap get(String key) {
        Bitmap value = super.get(key);
        // Increment usage count for value if value is contained in hardCahe
        if (value != null) {
            Integer usageCount = usingCounts.get(value);
            if (usageCount != null) {
                usingCounts.put(key, usageCount + 1);
            }
        }
        return value;
    }

    @Override
    public Bitmap remove(String key) {
        usingCounts.remove(key);
        return super.remove(key);
    }


    @Override
    protected String removeNext() {
        Integer minUsageCount = null;
        String leastUsedValue = null;
        Set> entries = usingCounts.entrySet();
        synchronized (usingCounts) {
            for (Entry entry : entries) {
                if (leastUsedValue == null) {
                    leastUsedValue = entry.getKey();
                    minUsageCount = entry.getValue();
                } else {
                    Integer lastValueUsage = entry.getValue();
                    if (lastValueUsage < minUsageCount) {
                        minUsageCount = lastValueUsage;
                        leastUsedValue = entry.getKey();
                    }
                }
            }
        }
        usingCounts.remove(leastUsedValue);
        return leastUsedValue;
    }

}

與ImageLoader不同的是,我們是用這個記錄

private final Map usingCounts = Collections.synchronizedMap(new HashMap());

而ImageLoader是用這種類型的記錄,其他的基本大同小異,有興趣的可以去這裡下載源碼。

private final Map usingCounts = Collections.synchronizedMap(new HashMap());

題外話:通過這篇博客,學習了更多的緩存算法,同時你們有沒有發現,很多地方都用到了Collection框架,而要用好這些,個人覺得去了解他們的原理是非常必要的,尤其是map和List集合,不管說是初學者還是大牛,畢竟萬丈高樓也是從平地蓋起的,基礎非常重要

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved