universal image loader源码分析——图片内存缓存策略分析

上一篇对于universal image loader源码分析——图片内存缓存做了大概的分析,本篇将对具体的图片内存缓存策略进行具体的分析。

1.FIFOLimitedMemoryCache

除了继承自LimitedMemoryCache限制了内存大小外,它使用的是FIFO先进先出策略。上源码:



所有,图片添加的时候是添加在queue的最后的,而移除则是移除第一个!这就是先进先出策略,先加入的先被移除。至于什么时候移除?当然是超过最大内存限制的时候哇!


2.LRULimitedMemoryCache

除了继承自LimitedMemoryCache限制了内存大小外,使用的是LinkedHashMap链表来存储强引用缓存,而对于所有图片使用弱引用缓存,就并没有其他特点了。

 

3.LargestLimitedMemoryCache

最大尺寸策略,继承自LimitedMemoryCache,无疑是优先移除图片内存占据最大空间的图片。

所以在进行存储的时候,需要存储该图片缓存的大小:

@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<Entry<Bitmap, Integer>> entries = valueSizes.entrySet();
   synchronized (valueSizes) {
      for (Entry<Bitmap, Integer> 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;
}

4.UsingFreqLimitedMemoryCache

使用频率缓存策略,继承自LimitedMemoryCache,即优先移除使用频率低的图片缓存。

所以,存储时存储的value则是使用频率了:

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

每当使用一次,即调用get方法一次,则加1:

@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
protected Bitmap removeNext() {
   Integer minUsageCount = null;
   Bitmap leastUsedValue = null;
   Set<Entry<Bitmap, Integer>> entries = usingCounts.entrySet();
   synchronized (usingCounts) {
      for (Entry<Bitmap, Integer> 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;
}
 

5.FuzzyKeyMemoryCache

关键字匹配缓存策略(暂时这么理解吧),直接实现了MemoryCache接口。根据注释我们可以知道,这个类一般用的很少,使用场景是:一图多尺寸缓存,可能理解起来会麻烦点。我们一般的一图多尺寸Url拼接是这样的:url_720x1280,也就是说,当key的前半部分相同时,作为同一个bitmap进行存储,而之前的bitmap则被直接移除。

从构造方法我们可以看出,需要传递一个比较器规则给它:

public FuzzyKeyMemoryCache(MemoryCache cache, Comparator<String> keyComparator) {
   this.cache = cache;
   this.keyComparator = keyComparator;
}
用于存储时进行比较,若相等则直接先移除再进行存储,说实话,在图片很多的时候,这么去遍历的话确实不太好,本来列表图片就对性能比较敏感。

@Override
public boolean put(String key, Bitmap value) {
   // Search equal key and remove this entry
   synchronized (cache) {
      String keyToRemove = null;
      for (String cacheKey : cache.keys()) {
         if (keyComparator.compare(key, cacheKey) == 0) {
            keyToRemove = cacheKey;
            break;
         }
      }
      if (keyToRemove != null) {
         cache.remove(keyToRemove);
      }
   }
   return cache.put(key, value);
}
而在源码中,有这么个默认的比较器:

private static final String URI_AND_SIZE_SEPARATOR = "_";

public static Comparator<String> createFuzzyKeyComparator() {
   return new Comparator<String>() {
      @Override
      public int compare(String key1, String key2) {
         String imageUri1 = key1.substring(0, key1.lastIndexOf(URI_AND_SIZE_SEPARATOR));
         String imageUri2 = key2.substring(0, key2.lastIndexOf(URI_AND_SIZE_SEPARATOR));
         return imageUri1.compareTo(imageUri2);
      }
   };
}
在imageload默认初始化的时候使用的便是上面这个比较器规则:
private void initEmptyFieldsWithDefaultValues() {
	...
	if (denyCacheImageMultipleSizesInMemory) {
   		memoryCache = new FuzzyKeyMemoryCache(memoryCache, MemoryCacheUtils.createFuzzyKeyComparator());
	}
	...
}

6.LimitedAgeMemoryCache

时长限制缓存策略,直接实现了MemoryCache接口。也就是说当图片存储的时间,超过了初始化缓存时设定的时间,则进行移除。

从其构造方法我们可以看出,传递的时间参数单位是秒:

public LimitedAgeMemoryCache(MemoryCache cache, long maxAge) {
   this.cache = cache;
   this.maxAge = maxAge * 1000; // to milliseconds
}

在这个缓存策略中,有个特别之处就是,它里面有个cache,也就是说,它可以在其他缓存策略的基础上,再添加一套缓存机制。

在存储的时候,将当前的时间进行存储:

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

7.LruMemoryCache

LRU缓存策略,最基本的限制大小的链式缓存策略。当图片被访问后,它会被移动到队列的头部,而当超过设置的最大内存后,将会优先移除底部的图片缓存。
值的一说的是它的内存判断方式:
@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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值