Android开源框架Universal-Image-Loader学习三——UsingFreqLimitedMemoryCache源码阅读



Universal-Image-Loader的内存缓存策略

技术分享

1. 只使用的是强引用缓存 

  • LruMemoryCache(这个类就是这个开源框架默认的内存缓存类,缓存的是bitmap的强引用)

2.使用强引用和弱引用相结合的缓存有

  • UsingFreqLimitedMemoryCache(如果缓存的图片总量超过限定值,先删除使用频率最小的bitmap)
  • LRULimitedMemoryCache(这个也是使用的lru算法,和LruMemoryCache不同的是,他缓存的是bitmap的弱引用)
  • FIFOLimitedMemoryCache(先进先出的缓存策略,当超过设定值,先删除最先加入缓存的bitmap)
  • LargestLimitedMemoryCache(当超过缓存限定值,先删除最大的bitmap对象)
  • LimitedAgeMemoryCache(当 bitmap加入缓存中的时间超过我们设定的值,将其删除)

3.只使用弱引用缓存

  • WeakMemoryCache(这个类缓存bitmap的总大小没有限制,唯一不足的地方就是不稳定,缓存的图片容易被回收掉)


继承关系:

技术分享

public class UsingFreqLimitedMemoryCache extends LimitedMemoryCache
public abstract class LimitedMemoryCache extends BaseMemoryCache
public abstract class BaseMemoryCache implements MemoryCache
public interface MemoryCache extends MemoryCacheAware<String, Bitmap>
@Deprecated
public interface MemoryCacheAware<K, V>

1、先来看MemoryCacheAware:


/* Interface for memory cache*/
@Deprecated
public interface MemoryCacheAware<K, V> {
    /*Puts value into cache by key
     * @return true - if value was put into cache successfully;false - if value was not put into cache
     */
    boolean put(K key, V value);
 
    /** Returns value by key. If there is no value for key then null will be returned. */
    V get(K key);
 
    /** Removes item by key */
    V remove(K key);
 
    /** Returns all keys of cache */
    Collection<K> keys();
 
    /** Remove all items from cache */
    void clear();
}

2、现在一般使用MemoryCache替代MemoryCacheAware:

MemoryCacheAware源码:

public interface MemoryCache extends MemoryCacheAware<String, Bitmap> {
}

3、BaseMemoryCache 源码:

/*为memory cache提供一些基本功能;提供object的引用(非强引用)存储*/
public abstract class BaseMemoryCache implements MemoryCache {
    /** 存储objects的非强引用,Collections.synchronizedMap保证线程安全*/
    private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>());
 
    @Override
    public Bitmap get(String key) {
        Bitmap result = null;
        Reference<Bitmap> 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<Bitmap> bmpRef = softMap.remove(key);
        return bmpRef == null ? null : bmpRef.get();
    }
 
    @Override
    public Collection<String> keys() {
        synchronized (softMap) {
            return new HashSet<String>(softMap.keySet());
        }
    }
 
    @Override
    public void clear() {
        softMap.clear();
    }
 
    /** Creates {@linkplain Reference not strong} reference of value */
    protected abstract Reference<Bitmap> createReference(Bitmap value);
}
 

4、LimitedMemoryCache源码:

/**
 * 限定的Cache.提供Object的存储。所有存储的bitmap的总内存大小不超过限定值
 * 注:该cache使用强引用和弱引用来存储Bitmaps;
 * 强引用——对于限额内的bitmaps
 * 弱应用——对于其他的Bitmaps
 */
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;
    /*AtomicInteger,一个提供原子操作的Integer的类,使得操作线程安全*/
    private final AtomicInteger cacheSize;
 
    /**
     * 包含存储objects的强引用。每个object都添加到最尾端;如果hard cache的大超过了限定值,首端的object将会被删除
     *(但它依然存在在softMap中,而且可以随时被GC回收)
     // 返回一个synchronizes封装的线程安全的List
        public static <T> List<T> synchronizedList(List<T> list)*/
    private final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>());
 
    /**构造函数:sizeLimit单位bytes */
    public LimitedMemoryCache(int sizeLimit) {
        this.sizeLimit = sizeLimit;
        cacheSize = new AtomicInteger();
        /**检测避免sizeLimit值设置过大 */
        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);
        }
    }

    /**操作成功返回true,操作失败返回false 
       先尝试将Bitmap添加至hard cache,再将其添加至soft cache*/
    @Override
    public boolean put(String key, Bitmap value) {
        boolean putSuccessfully = false;
        
        int valueSize = getSize(value);    //抽象函数,返回Bitmap的大小值
        int sizeLimit = getSizeLimit();    //返回sizeLimit
        int curCacheSize = cacheSize.get();//返回cacheSize的当前值
         /**如果添加的bitmap的size大于sizeLimit,则直接不将其添加至hard cache*/
        if (valueSize < sizeLimit) {
            /**判断新添加的Object的valueSize加上当前cache中已有object的curCacheSize超过限定值,则会删除适当Bitmap*/
            while (curCacheSize + valueSize > sizeLimit) {
                Bitmap removedValue = removeNext();    //abstract函数,返回需要删除的下一个Bitmap
                if (hardCache.remove(removedValue)) {
                    curCacheSize = cacheSize.addAndGet(-getSize(removedValue));
                }
            }
            hardCache.add(value);          //添加到LinkedList<Bitmap>尾部       
            cacheSize.addAndGet(valueSize);//即cacheSize+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
    publicvoid clear() {
        hardCache.clear();
        cacheSize.set(0);
        super.clear();
    }
 
    protected int getSizeLimit() {
        return sizeLimit;
    }
 
    protected abstract int getSize(Bitmap value);
 
    protected abstract Bitmap removeNext();
}
 

5、UsingFreqLimitedMemoryCache源码:(关键在于get中更新使用频率)

/**
 * Limited {@link Bitmap bitmap} cache. Provides {@link Bitmap bitmaps} storing. Size of all stored bitmaps will not to
 * exceed size limit. When cache reaches limit size then the bitmap which used the least frequently is deleted from
 * cache(删除最少使用频率的bitmap)
 * NOTE:使用强引用和弱引用;
 * 强引用:for limited count of Bitmaps (depends on cache size)
 * 弱应用:for all other cached Bitmaps
 */
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<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());
 
    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);
        // 如果value存在,则usageCount+ 1;
        if (value != null) {
            Integer usageCount = usingCounts.get(value);
            if (usageCount != null) {
                // 更新value对应的usageCount的值
                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<Entry<Bitmap, Integer>> entries = usingCounts.entrySet();
        synchronized (usingCounts) {
            for (Entry<Bitmap, Integer> entry : entries) {
               //初始化leastUsedValue
                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<Bitmap> createReference(Bitmap value) {
        return new WeakReference<Bitmap>(value);
    }
}






郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。