[关闭]
@xujun94 2016-07-24T22:44:32.000000Z 字数 18536 阅读 993

带你了解Android常见的内存缓存算法

本片博客主要简介以下两个问题

  1. 介绍一下常见的内存缓存算法
  2. 怎样实现这些算法

文章首发地址CSDN博客:
大家应该对ImageLoader这个框架都不陌生吧,一个很强大的图片加载框架,虽然作者去年的时候已经停止维护了,但里面的许多东西还是值得我们去学习的。本篇博客讲解的内存缓存算法正是基于ImageLoader的实现基础之上的

常见的几种缓存算法

也就是当内存缓存达到设定的最大值时将内存缓存中近期最少使用的对象移除,有效的避免了OOM的出现。

对每个缓存对象计算他们被使用的频率。把最不常用的缓存对象换走。

这是一个低负载的算法,并且对缓存对象的管理要求不高。通过一个队列去跟踪所有的缓存对象,最近最常用的缓存对象放在后面,而更早的缓存对象放在前面,当缓存容量满时,排在前面的缓存对象会被踢走,然后把新的缓存对象加进去。

通过绝对的时间周期去失效那些缓存对象。对于新增的对象,保存特定的时间。

超过指定缓存的话,每次移除栈最大内存的缓存的对象

下面我们一起来看一下ImageLoader是怎样实现这些算法的

首先我们一起先来看一下类UML图

源码分析

  1. public abstract class BaseMemoryCache implements MemoryCache {
  2. /** Stores not strong references to objects */
  3. private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>());
  4. @Override
  5. public Bitmap get(String key) {
  6. Bitmap result = null;
  7. Reference<Bitmap> reference = softMap.get(key);
  8. if (reference != null) {
  9. result = reference.get();
  10. }
  11. return result;
  12. }
  13. @Override
  14. public boolean put(String key, Bitmap value) {
  15. softMap.put(key, createReference(value));
  16. return true;
  17. }
  18. @Override
  19. public Bitmap remove(String key) {
  20. Reference<Bitmap> bmpRef = softMap.remove(key);
  21. return bmpRef == null ? null : bmpRef.get();
  22. }
  23. @Override
  24. public Collection<String> keys() {
  25. synchronized (softMap) {
  26. return new HashSet<String>(softMap.keySet());
  27. }
  28. }
  29. @Override
  30. public void clear() {
  31. softMap.clear();
  32. }
  33. /** Creates {@linkplain Reference not strong} reference of value */
  34. protected abstract Reference<Bitmap> createReference(Bitmap value);
  35. }

其实就是保存着一份弱引用而已,而它的父类Memory只是定义了几个接口方法,统一标准而已

  1. public abstract class LimitedMemoryCache extends BaseMemoryCache {
  2. private static final int MAX_NORMAL_CACHE_SIZE_IN_MB = 16;
  3. private static final int MAX_NORMAL_CACHE_SIZE = MAX_NORMAL_CACHE_SIZE_IN_MB * 1024 * 1024;
  4. private final int sizeLimit;
  5. private final AtomicInteger cacheSize;
  6. /**
  7. * Contains strong references to stored objects. Each next object is added last. If hard cache size will exceed
  8. * limit then first object is deleted (but it continue exist at {@link #softMap} and can be collected by GC at any
  9. * time)
  10. */
  11. private final List<Bitmap> hardCache = Collections.synchronizedList(
  12. new LinkedList<Bitmap>());
  13. /** @param sizeLimit Maximum size for cache (in bytes) */
  14. public LimitedMemoryCache(int sizeLimit) {
  15. this.sizeLimit = sizeLimit;
  16. cacheSize = new AtomicInteger();
  17. if (sizeLimit > MAX_NORMAL_CACHE_SIZE) {
  18. L.w("You set too large memory cache size (more than %1$d Mb)",
  19. MAX_NORMAL_CACHE_SIZE_IN_MB);
  20. }
  21. }
  22. @Override
  23. public boolean put(String key, Bitmap value) {
  24. boolean putSuccessfully = false;
  25. // Try to add value to hard cache
  26. int valueSize = getSize(value);
  27. int sizeLimit = getSizeLimit();
  28. int curCacheSize = cacheSize.get();
  29. if (valueSize < sizeLimit) {
  30. while (curCacheSize + valueSize > sizeLimit) {
  31. Bitmap removedValue = removeNext();
  32. if (hardCache.remove(removedValue)) {
  33. curCacheSize = cacheSize.addAndGet(-getSize(removedValue));
  34. }
  35. }
  36. hardCache.add(value);
  37. cacheSize.addAndGet(valueSize);
  38. putSuccessfully = true;
  39. }
  40. // Add value to soft cache
  41. super.put(key, value);
  42. return putSuccessfully;
  43. }
  44. @Override
  45. public Bitmap remove(String key) {
  46. Bitmap value = super.get(key);
  47. if (value != null) {
  48. if (hardCache.remove(value)) {
  49. cacheSize.addAndGet(-getSize(value));
  50. }
  51. }
  52. return super.remove(key);
  53. }
  54. @Override
  55. public void clear() {
  56. hardCache.clear();
  57. cacheSize.set(0);
  58. super.clear();
  59. }
  60. protected int getSizeLimit() {
  61. return sizeLimit;
  62. }
  63. protected abstract int getSize(Bitmap value);
  64. protected abstract Bitmap removeNext();
  65. }

LimitedMemoryCache所做的工作可以分为以下几步

注意事项

结合BaseMemoryCache和LimitedMemoryCache,我们可以知道LimitedMemoryCache的子类,至少可以访问两份Bitmap 的缓存,一份是BaseMemoryCache所拥有的softMap ,是弱引用;一份是LimitedMemoryCachehar所拥有的hardCache 集合

  1. //父类BaseMemoryCache的成员变量,并且每次在操作的时候都会把bitmap的弱引用存进去
  2. private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(
  3. new HashMap<String, Reference<Bitmap>>());
  4. //LimitedMemoryCache的成员变量,缓存的bitmap是强引用
  5. private final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>());

有人可能会有疑问了这些成员变量不是私有的吗?为什么说LimitedMemoryCache的子类,至少可以访问两份引用,这点我们可以从他们的put方法中知道

  1. @Override
  2. public boolean put(String key, Bitmap value) {
  3. boolean putSuccessfully = false;
  4. // Try to add value to hard cache
  5. int valueSize = getSize(value);
  6. int sizeLimit = getSizeLimit();
  7. int curCacheSize = cacheSize.get();
  8. if (valueSize < sizeLimit) {
  9. while (curCacheSize + valueSize > sizeLimit) {
  10. Bitmap removedValue = removeNext();
  11. if (hardCache.remove(removedValue)) {
  12. curCacheSize = cacheSize.addAndGet(-getSize(removedValue));
  13. }
  14. }
  15. hardCache.add(value);
  16. cacheSize.addAndGet(valueSize);
  17. putSuccessfully = true;
  18. }
  19. // Add value to soft cache
  20. super.put(key, value);
  21. return putSuccessfully;
  22. }

同理LimitedMemoryCache的子类put也会调用LimitedMemoryCache的put方法,代码见下面分析。

同时从上面的分析当中我们可以知道主要关心put和removeNext()这两个方法就可以了,put()方法其实就是把bitmap对象存进我们的queue队列中

下面我们在看一下UsingFreqLimitedMemoryCache是怎样实现的?

  1. public class UsingFreqLimitedMemoryCache extends LimitedMemoryCache {
  2. /**
  3. * Contains strong references to stored objects (keys) and last object usage date (in milliseconds). If hard cache
  4. * size will exceed limit then object with the least frequently usage is deleted (but it continue exist at
  5. * {@link #softMap} and can be collected by GC at any time)
  6. */
  7. private final Map<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());
  8. public UsingFreqLimitedMemoryCache(int sizeLimit) {
  9. super(sizeLimit);
  10. }
  11. @Override
  12. public boolean put(String key, Bitmap value) {
  13. if (super.put(key, value)) {
  14. usingCounts.put(value, 0);
  15. return true;
  16. } else {
  17. return false;
  18. }
  19. }
  20. @Override
  21. public Bitmap get(String key) {
  22. Bitmap value = super.get(key);
  23. // Increment usage count for value if value is contained in hardCahe
  24. if (value != null) {
  25. Integer usageCount = usingCounts.get(value);
  26. if (usageCount != null) {
  27. usingCounts.put(value, usageCount + 1);
  28. }
  29. }
  30. return value;
  31. }
  32. @Override
  33. public Bitmap remove(String key) {
  34. Bitmap value = super.get(key);
  35. if (value != null) {
  36. usingCounts.remove(value);
  37. }
  38. return super.remove(key);
  39. }
  40. @Override
  41. public void clear() {
  42. usingCounts.clear();
  43. super.clear();
  44. }
  45. @Override
  46. protected int getSize(Bitmap value) {
  47. return value.getRowBytes() * value.getHeight();
  48. }
  49. @Override
  50. protected Bitmap removeNext() {
  51. Integer minUsageCount = null;
  52. Bitmap leastUsedValue = null;
  53. Set<Entry<Bitmap, Integer>> entries = usingCounts.entrySet();
  54. synchronized (usingCounts) {
  55. for (Entry<Bitmap, Integer> entry : entries) {
  56. if (leastUsedValue == null) {
  57. leastUsedValue = entry.getKey();
  58. minUsageCount = entry.getValue();
  59. } else {
  60. Integer lastValueUsage = entry.getValue();
  61. if (lastValueUsage < minUsageCount) {
  62. minUsageCount = lastValueUsage;
  63. leastUsedValue = entry.getKey();
  64. }
  65. }
  66. }
  67. }
  68. usingCounts.remove(leastUsedValue);
  69. return leastUsedValue;
  70. }
  71. @Override
  72. protected Reference<Bitmap> createReference(Bitmap value) {
  73. return new WeakReference<Bitmap>(value);
  74. }
  75. }

思路解析

  1. 当我们调用put方法,把bitmap存进内存的时候,他会判断是否超出我们的最大值,超出我们的最大值就会调用removeNext();来获得我们将要移除的bitmap对象,最终再调用hardCache.remove(removedValue)去移除它。

```java
@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;
}
···


FIFOLimitedMemoryCache源码分析

  1. public class FIFOLimitedMemoryCache extends LimitedMemoryCache {
  2. private final List<Bitmap> queue = Collections.synchronizedList(new LinkedList<Bitmap>());
  3. public FIFOLimitedMemoryCache(int sizeLimit) {
  4. super(sizeLimit);
  5. }
  6. @Override
  7. public boolean put(String key, Bitmap value) {
  8. if (super.put(key, value)) {
  9. queue.add(value);
  10. return true;
  11. } else {
  12. return false;
  13. }
  14. }
  15. @Override
  16. public Bitmap remove(String key) {
  17. Bitmap value = super.get(key);
  18. if (value != null) {
  19. queue.remove(value);
  20. }
  21. return super.remove(key);
  22. }
  23. @Override
  24. public void clear() {
  25. queue.clear();
  26. super.clear();
  27. }
  28. @Override
  29. protected int getSize(Bitmap value) {
  30. return value.getRowBytes() * value.getHeight();
  31. }
  32. @Override
  33. protected Bitmap removeNext() {
  34. return queue.remove(0);
  35. }
  36. @Override
  37. protected Reference<Bitmap> createReference(Bitmap value) {
  38. return new WeakReference<Bitmap>(value);
  39. }
  40. }

* 2)remove方法其实就是一出队列的第一个bitmap对象,将先进先出,符合我们的FIFO原则

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

  1. ## LargestLimitedMemoryCache源码分析
  2. ```java
  3. public class LargestLimitedMemoryCache extends LimitedMemoryCache {
  4. /**
  5. * Contains strong references to stored objects (keys) and sizes of the objects. If hard cache
  6. * size will exceed limit then object with the largest size is deleted (but it continue exist at
  7. * {@link #softMap} and can be collected by GC at any time)
  8. */
  9. private final Map<Bitmap, Integer> valueSizes = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());
  10. public LargestLimitedMemoryCache(int sizeLimit) {
  11. super(sizeLimit);
  12. }
  13. @Override
  14. public boolean put(String key, Bitmap value) {
  15. if (super.put(key, value)) {
  16. valueSizes.put(value, getSize(value));
  17. return true;
  18. } else {
  19. return false;
  20. }
  21. }
  22. @Override
  23. public Bitmap remove(String key) {
  24. Bitmap value = super.get(key);
  25. if (value != null) {
  26. valueSizes.remove(value);
  27. }
  28. return super.remove(key);
  29. }
  30. //这里我们省略若干个方法,有兴趣的话讲源码去,下面有提供源码下载地址
  31. @Override
  32. protected Bitmap removeNext() {
  33. Integer maxSize = null;
  34. Bitmap largestValue = null;
  35. Set<Entry<Bitmap, Integer>> entries = valueSizes.entrySet();
  36. synchronized (valueSizes) {
  37. for (Entry<Bitmap, Integer> entry : entries) {
  38. if (largestValue == null) {
  39. largestValue = entry.getKey();
  40. maxSize = entry.getValue();
  41. } else {
  42. Integer size = entry.getValue();
  43. if (size > maxSize) {
  44. maxSize = size;
  45. largestValue = entry.getKey();
  46. }
  47. }
  48. }
  49. }
  50. valueSizes.remove(largestValue);
  51. return largestValue;
  52. }
  53. }
  54. <div class="md-section-divider"></div>

同样我们只关心put方法和removeNext()方法

  1. @Override
  2. public boolean put(String key, Bitmap value) {
  3. if (super.put(key, value)) {
  4. valueSizes.put(value, getSize(value));
  5. return true;
  6. }else {
  7. return false;
  8. }
  9. }
  10. @Override
  11. protected Bitmap removeNext() {
  12. Integer maxSize = null;
  13. Bitmap largestValue = null;
  14. Set<Entry<Bitmap, Integer>> entries = valueSizes.entrySet();
  15. synchronized (valueSizes) {
  16. for (Entry<Bitmap, Integer> entry : entries) {
  17. if (largestValue == null) {
  18. largestValue = entry.getKey();
  19. maxSize = entry.getValue();
  20. } else {
  21. Integer size = entry.getValue();
  22. if (size > maxSize) {
  23. maxSize = size;
  24. largestValue = entry.getKey();
  25. }
  26. }
  27. }
  28. }
  29. valueSizes.remove(largestValue);
  30. return largestValue;
  31. }
  32. <div class="md-section-divider"></div>

下面我们来看一下LruMemoryCache是怎样实现的

源码我们就不贴出来了
主要逻辑在put方法中

  1. // 存储bitmap对象,在构造方法里面初始化
  2. private final LinkedHashMap<String, Bitmap> map;
  3. /** Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue. */
  4. @Override
  5. public final boolean put(String key, Bitmap value) {
  6. if (key == null || value == null) {
  7. throw new NullPointerException("key == null || value == null");
  8. }
  9. synchronized (this) {
  10. size += sizeOf(key, value);
  11. Bitmap previous = map.put(key, value);
  12. if (previous != null) {
  13. size -= sizeOf(key, previous);
  14. }
  15. }
  16. trimToSize(maxSize);
  17. return true;
  18. }
  19. <div class="md-section-divider"></div>

当我们把bitmap存进内存的时候,他会trimToSize(maxSize)这个方法去判断我们是否超过我们规定内存的最大值,超过的话移除掉最先添加进来的那个

  1. private void trimToSize(int maxSize) {
  2. while (true) {
  3. String key;
  4. Bitmap value;
  5. synchronized (this) {
  6. if (size < 0 || (map.isEmpty() && size != 0)) {
  7. throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");
  8. }
  9. if (size <= maxSize || map.isEmpty()) {
  10. break;
  11. }
  12. Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next();
  13. if (toEvict == null) {
  14. break;
  15. }
  16. key = toEvict.getKey();
  17. value = toEvict.getValue();
  18. map.remove(key);
  19. size -= sizeOf(key, value);
  20. }
  21. }
  22. }
  23. <div class="md-section-divider"></div>

下面我们来看一下LimitedAgeMemoryCache 是怎样实现的

  1. /**
  2. * Decorator for {@link MemoryCache}. Provides special feature for cache: if some cached object age exceeds defined
  3. * value then this object will be removed from cache.
  4. *
  5. * 采用装饰着模式,计算对象的最大存活时间
  6. * 在get方法的时候判断大于的移除掉
  7. *
  8. */
  9. public class LimitedAgeMemoryCache implements MemoryCache {
  10. private final MemoryCache cache;
  11. private final long maxAge;
  12. private final Map<String, Long> loadingDates = Collections.synchronizedMap(new HashMap<String, Long>());
  13. /**
  14. * @param cache Wrapped memory cache
  15. * @param maxAge Max object age <b>(in seconds)</b>. If object age will exceed this value then it'll be removed from
  16. * cache on next treatment (and therefore be reloaded).
  17. */
  18. public LimitedAgeMemoryCache(MemoryCache cache, long maxAge) {
  19. this.cache = cache;
  20. this.maxAge = maxAge * 1000; // to milliseconds
  21. }
  22. @Override
  23. public boolean put(String key, Bitmap value) {
  24. boolean putSuccesfully = cache.put(key, value);
  25. if (putSuccesfully) {
  26. loadingDates.put(key, System.currentTimeMillis());
  27. }
  28. return putSuccesfully;
  29. }
  30. @Override
  31. public Bitmap get(String key) {
  32. Long loadingDate = loadingDates.get(key);
  33. if (loadingDate != null && System.currentTimeMillis() - loadingDate > maxAge) {
  34. cache.remove(key);
  35. loadingDates.remove(key);
  36. }
  37. return cache.get(key);
  38. }
  39. @Override
  40. public Bitmap remove(String key) {
  41. loadingDates.remove(key);
  42. return cache.remove(key);
  43. }
  44. @Override
  45. public Collection<String> keys() {
  46. return cache.keys();
  47. }
  48. @Override
  49. public void clear() {
  50. cache.clear();
  51. loadingDates.clear();
  52. }
  53. }
  54. <div class="md-section-divider"></div>

分析

* 3)那我们是怎样保存这些的存活时间的呢,其实很简单?就是用一个loadingDates集合来保存,在我们put的时候,把当前的时间存进去,源码体现如下

  1. //成员变量,保持存活时间的map集合
  2. private final Map<String, Long> loadingDates = Collections.synchronizedMap(
  3. new HashMap<String, Long>());
  4. @Override
  5. public boolean put(String key, Bitmap value) {
  6. boolean putSuccesfully = cache.put(key, value);
  7. if (putSuccesfully) {
  8. loadingDates.put(key, System.currentTimeMillis());
  9. }
  10. return putSuccesfully;
  11. }
  12. <div class="md-section-divider"></div>

感觉ImageLoader在实现FIFOLimitedMemoryCache算法的时候还是有一点缺陷,为什么呢?

到此ImageLoader内存的缓存算法源码分析为止,下面我稍微改一下实现方式,内存里面不再保存着两份引用了,bitmap的缓存只保存着一份引用。


自己实现的内存缓存算法

类UML图

其实跟ImageLoader实现的也没有多大区别,只是我去除了弱引用,每个实现类里面不像LimitedMemoryCache的实现类一样持有两份引用而已

首先我们来看一下LimitedMemoryCache是怎样实现的

  1. public abstract class LimitedMemoryCache implements MemoryCache {
  2. private static final int MAX_NORMAL_CACHE_SIZE_IN_MB = 16;
  3. private static final int MAX_NORMAL_CACHE_SIZE = MAX_NORMAL_CACHE_SIZE_IN_MB * 1024 * 1024;
  4. private final int sizeLimit;
  5. public static final String TAG="tag";
  6. private final AtomicInteger cacheSize;
  7. private final Map<String, Bitmap> mMap= Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>());
  8. public LimitedMemoryCache(int sizeLimit) {
  9. this.sizeLimit = sizeLimit;
  10. cacheSize = new AtomicInteger();
  11. if (sizeLimit > MAX_NORMAL_CACHE_SIZE) {
  12. Log.w(TAG,"You set too large memory cache size (more than %1$d Mb)"+ MAX_NORMAL_CACHE_SIZE_IN_MB);
  13. }
  14. }
  15. @Override
  16. public boolean put(String key, Bitmap value) {
  17. boolean putSuccessfully = false;
  18. // Try to add value to hard cache
  19. int valueSize = getSize(value);
  20. int sizeLimit = getSizeLimit();
  21. int curCacheSize = cacheSize.get();
  22. if (valueSize < sizeLimit) {
  23. while (curCacheSize + valueSize > sizeLimit) {
  24. String removeKey = removeNext();
  25. if(removeKey==null){
  26. break;
  27. }
  28. Bitmap bitmap = mMap.remove(key);
  29. if(bitmap!=null){
  30. curCacheSize = cacheSize.addAndGet(-getSize(bitmap));
  31. }
  32. }
  33. mMap.put(key,value);
  34. cacheSize.addAndGet(valueSize);
  35. putSuccessfully = true;
  36. }
  37. return putSuccessfully;
  38. }
  39. @Override
  40. public Bitmap remove(String key) {
  41. return mMap.remove(key);
  42. }
  43. @Override
  44. public Bitmap get(String key) {
  45. return mMap.get(key);
  46. }
  47. @Override
  48. public void clear() {
  49. mMap.clear();
  50. cacheSize.set(0);
  51. }
  52. protected int getSizeLimit() {
  53. return sizeLimit;
  54. }
  55. @Override
  56. public Collection<String> keys() {
  57. synchronized (mMap) {
  58. return new HashSet<String>(mMap.keySet());
  59. }
  60. }
  61. protected abstract int getSize(Bitmap value);
  62. protected abstract String removeNext();
  63. }
  64. <div class="md-section-divider"></div>

LimitedMemoryCache所做的工作可以分为以下几步

  1. //在构造方法里面初始化
  2. private final Map<String, Bitmap> mMap;
  3. <div class="md-section-divider"></div>

下面我们来看一下

  1. public class UsingFreqLimitedMemoryCache extends LimitedMemoryCache {
  2. private final Map<String, Integer> usingCounts = Collections.synchronizedMap(new HashMap<String, Integer>());
  3. //这里省略了若干个方法
  4. @Override
  5. public boolean put(String key, Bitmap value) {
  6. if (super.put(key, value)) {
  7. usingCounts.put(key, 0);
  8. return true;
  9. } else {
  10. return false;
  11. }
  12. }
  13. @Override
  14. public Bitmap get(String key) {
  15. Bitmap value = super.get(key);
  16. // Increment usage count for value if value is contained in hardCahe
  17. if (value != null) {
  18. Integer usageCount = usingCounts.get(value);
  19. if (usageCount != null) {
  20. usingCounts.put(key, usageCount + 1);
  21. }
  22. }
  23. return value;
  24. }
  25. @Override
  26. public Bitmap remove(String key) {
  27. usingCounts.remove(key);
  28. return super.remove(key);
  29. }
  30. @Override
  31. protected String removeNext() {
  32. Integer minUsageCount = null;
  33. String leastUsedValue = null;
  34. Set<Entry<String, Integer>> entries = usingCounts.entrySet();
  35. synchronized (usingCounts) {
  36. for (Entry<String, Integer> entry : entries) {
  37. if (leastUsedValue == null) {
  38. leastUsedValue = entry.getKey();
  39. minUsageCount = entry.getValue();
  40. } else {
  41. Integer lastValueUsage = entry.getValue();
  42. if (lastValueUsage < minUsageCount) {
  43. minUsageCount = lastValueUsage;
  44. leastUsedValue = entry.getKey();
  45. }
  46. }
  47. }
  48. }
  49. usingCounts.remove(leastUsedValue);
  50. return leastUsedValue;
  51. }
  52. }
  53. <div class="md-section-divider"></div>

与ImageLoader不同的是,我们是用这个记录

  1. private final Map<String, Integer> usingCounts = Collections.synchronizedMap(new HashMap<String, Integer>());
  2. <div class="md-section-divider"></div>

而ImageLoader是用这种类型的记录,其他的基本大同小异,有兴趣的可以去这里下载源码

  1. private final Map<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());

题外话:通过这篇博客,学习了更多的缓存算法,同时你们有没有发现,很多地方都用到了Collection框架,而要用好这些,个人觉得去了解他们的原理是非常必要的,尤其是map和List集合,不管说是初学者还是大牛,毕竟万丈高楼也是从平地盖起的,基础非常重要

**转载请注明原博客地址: **

源码参考地址 ImagerLoader:

**源码下载地址: **

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注