UniversalImageLoader源码学习——LruMemoryCache内存缓存

来源:互联网 发布:mac系统中怎么激活ai 编辑:程序博客网 时间:2024/06/05 10:18

之前我们分析了ImageLoader的源码,它的缓存策略较为简单,在实际应用中我们更多的用的是UniversalImageLoader,下面我们阅读下它的源码,分析下它的缓存逻辑。
UniversalImageLoader采用三级缓存策略,分别是内存缓存、硬盘缓存、网络缓存。
我们今天先看内存缓存:
1、首先定义一个借口MemoryCache,供外界调用,在其中分别定义put、get、remove、clear抽象方法,用于对缓存进行操作,另定义keys()方法,用于获取关键字集合。代码如下:

public abstract interface MemoryCache{  public abstract boolean put(String paramString, Bitmap paramBitmap);  public abstract Bitmap get(String paramString);  public abstract Bitmap remove(String paramString);  public abstract Collection<String> keys();  public abstract void clear();}

2、看抽象类BaseMemoryCache。
private final Map

  public Collection<String> keys()  {    synchronized (this.softMap) {      return new HashSet(this.softMap.keySet());    }  }

3、看抽象类LimitedMemoryCache,此类主要是对cache的大小做了限定,当图片缓慢满了之后,按一定策略选出需要删除的Bitmap缓存,具体删除策略,由其子类实现。这里需注意线程同步问题,AtomicInteger是提供了原子操作的Integer的类,是线程安全的。

4、查看 FIFOLimitedMemoryCache、LRULimitedMemoryCache、LargestLimitedMemoryCache、UsingFreqLimitedMemoryCache
这四个类都是MemoryCache的实现类,继承自LimitedMemoryCache。通过名字可以看出,它们分别对应不同的缓存策略:

FIFOLimitedMemoryCache 对应的是先进先出的缓存策略,即当图片缓存满了之后,首先删除的是最先进入缓存区的图片,此时的引用为WeakReference。具体实现如下:

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

LRULimitedMemoryCache 对应是最近最少使用的缓存测试,即当图片缓存满了之后,首先删除的是最近最不常用的图片,此时的引用为WeakReference。具体实现如下:

  private final Map<String, Bitmap> lruCache = Collections.synchronizedMap(new LinkedHashMap(10, 1.1F, true));//设定初始容量为10,加载因子为1.1,按访问顺序排序的Map。  protected Bitmap removeNext()  {    Bitmap mostLongUsedValue = null;    synchronized (this.lruCache) {      Iterator it = this.lruCache.entrySet().iterator();      if (it.hasNext()) {        Map.Entry entry = (Map.Entry)it.next();        mostLongUsedValue = (Bitmap)entry.getValue();        it.remove();      }    }    return mostLongUsedValue;  }

LargestLimitedMemoryCache 对应是按存储大小进行删除的缓存策略,即当图片缓存满了之后,对Map进行遍历,首先删除的占用存储空间最大的图片,此时的引用为WeakReference。具体实现如下:

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

UsingFreqLimitedMemoryCache对应是按使用次数多少进行删除的缓存策略,即当图片缓存满了之后,对Map进行遍历,首先删除的是使用次数最少的图片,此时的引用为WeakReference。具体实现如下:

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

4、查看FuzzyKeyMemoryCache 和LimitedAgeMemoryCache 类
FuzzyKeyMemoryCache 在put的时候,会先删除具有相同意义的key,然后再添加,具体实现如下:

 public boolean put(String key, Bitmap value)  {    synchronized (this.cache) {      String keyToRemove = null;      for (String cacheKey : this.cache.keys()) {        if (this.keyComparator.compare(key, cacheKey) == 0) {          keyToRemove = cacheKey;          break;        }      }      if (keyToRemove != null) {        this.cache.remove(keyToRemove);      }    }    return this.cache.put(key, value);  }

LimitedAgeMemoryCache对应最大有效时限的缓存策略,在put的时候,存储当前时间戳,在get的时候会判断当前元素的存储时限是否大于最大时限,如果大于,获取之后则直接删除,具体实现如下:

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

5、查看LruMemoryCache
LruMemoryCache 有缓存存储的最大容量上限,put时,如果key之前有对应的value,在计算当前使用的容量时,需要先减去之前value的大小,再加上新的value的大小。同时,删除最老的键值对,直到剩下的键值对的总值少于或者等于标准最大值,具体实现如下:

  public final boolean put(String key, Bitmap value)  {    if ((key == null) || (value == null)) {      throw new NullPointerException("key == null || value == null");    }    synchronized (this) {      this.size += sizeOf(key, value);      Bitmap previous = (Bitmap)this.map.put(key, value);      if (previous != null) {        this.size -= sizeOf(key, previous);      }    }    trimToSize(this.maxSize);    return true;  }
  private void trimToSize(int maxSize)  {    while (true)      synchronized (this) {        if ((this.size < 0) || ((this.map.isEmpty()) && (this.size != 0))) {          throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");        }        if ((this.size <= maxSize) || (this.map.isEmpty()))        {          break;        }        Map.Entry toEvict = (Map.Entry)this.map.entrySet().iterator().next();        if (toEvict == null) {          break;        }        String key = (String)toEvict.getKey();        Bitmap value = (Bitmap)toEvict.getValue();        this.map.remove(key);        this.size -= sizeOf(key, value);      }  }

同时,我们在这里特殊说明下,UniversalImageLoader默认的内存缓存模式就是这个,缓存的是bitmap的强引用,其调用方式在DefaultConfigurationFactory:

 public static MemoryCache createMemoryCache(Context context, int memoryCacheSize)  {    if (memoryCacheSize == 0) {      ActivityManager am = (ActivityManager)context.getSystemService("activity");      int memoryClass = am.getMemoryClass();      if ((hasHoneycomb()) && (isLargeHeap(context))) {        memoryClass = getLargeMemoryClass(am);      }      memoryCacheSize = 1048576 * memoryClass / 8;    }    return new LruMemoryCache(memoryCacheSize);  }
0 0
原创粉丝点击