• Android-Universal-Image-Loader学习笔记(3)--内存缓存


    前面的两篇博客写了文件缓存。如今说说Android-Universal-Image-Loader的内存缓存。该内存缓存涉及到的类如图所看到的

    这些类的继承关系例如以下图所看到的:

    如同文件缓存一样,内存缓存涉及的接口也有两个:MemoryCacheAware 和MemoryCache,当中MemoryCache仅仅是简单的继承了MemoryCacheAware并没有声明其它的方法。

    MemoryCacheAware接口的方法例如以下:

    @Deprecated
    public interface MemoryCacheAware<K, V> {
    	/**
    	 *依据key值把value放入缓存
    	 * @return 假设放入缓存成功的话就返回true,反之返回false
    	 */
    	boolean put(K key, V value);
    	/**依据key从缓存中获取数据,没有相关数据则返回null*/
    	V get(K key);
    	/** 依据key从缓存中删除数据*/
    	void remove(K key);
    	/** 返回缓存中全部的key */
    	Collection<K> keys();
    	/** 清空缓存*/
    	void clear();
    }

    以下具体介绍这些缓存的作用以及实现方式,先从BaseMemoryCache以及其子类開始

    BaseMemoryCache

              该类是一个抽象类,提供了一个map,用来缓存Bitmap的弱引用:

      private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>());

        当中softMap的value字段就是保存了Bimmap的引用类型,因为Reference又分为强引用。弱引用,软引用以及虚引用。所以该该类另外还提供了一个抽象方法createReference(Bitmap value)让子类重写,依据不同的要求来返回不同的应用类型。该抽象方法是将Bitmap转换成一个Reference。在调用BaseMemoryCache的put方法时调用。

    /**依据value创建一个弱引用对象。该类为抽象类。供子类实现 */
    	protected abstract Reference<Bitmap> createReference(Bitmap value);
    
        @Override
        public boolean put(String key, Bitmap value) {
            softMap.put(key, createReference(value));
            return true;
        }
    

       LimitedMemoryCache:

                  该类为抽象类。继承了BaseMemoryChache。对缓存进行了两个限制:

             1)  限制每个缓存图片的最大值:用sizeLimit来作为标致,对大于sizeLimit大小的bitmap对象。调用父类的put方法保存bitmap的弱引用。

    否则在保存弱引用的同一时候,把Bitmap对象的强引用用类型为LinkedList变量hardCache缓存起来,

           2)  相同用sizeLimit来限制整个缓存的大小。对是否超出缓存大小的限制在put方法被调用的时候会做推断。假设缓存大小超出限制就从LinkedList中删除相应的bitmap对象,详细的删除策略有该类的抽象方法remoeNext()提供。详细的在子父类中实现(比方有的是删除最大的那个bitMap,以及依据FIFO算法删除等等),这是典型的模板方法模式的应用。详细的模板方法为romoveNext()getSize()由相应的子类实现。

    注意put方法的返回值,当要增加的bitMap的大小超过sizeLimit的就返回false。否则返回true(在子类中调用该put方法。返回true说明对缓存进行了相应的删除操作)

    private final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>());<span style="color:#0000C0;">//hardCache</span><span style="color:#0000C0;">仅仅是在此类中仅仅是用来对缓存是否超过</span><span style="color:#0000C0;">sizeLimit</span><span style="color:#0000C0;">做推断。</span>
    	//bitMap放入缓存
    	@Override
    	public boolean put(String key, Bitmap value) {
    		boolean putSuccessfully = false;
    		// Try to add value to hard cache
    		//getSize方法为抽象方法,由子类实现
    		int valueSize = getSize(value);
    		int sizeLimit = this.sizeLimit;
    		int curCacheSize = cacheSize.get();
    		//当bitmap的大小小于sizeLimit的大小时
    		if (valueSize < sizeLimit) {
    			//对缓存进行删除操作,使之不超过siezeLimit的限制,。我们
    			while (curCacheSize + valueSize > sizeLimit) {
    				Bitmap removedValue = removeNext();//removeNext()为抽象方法,由不同的子类提供不同的删除策略
    				if (hardCache.remove(removedValue)) {
    					curCacheSize = cacheSize.addAndGet(-getSize(removedValue));
    				}
    			}
    			//放入缓存
    			hardCache.add(value);
    			//设置缓存大小
    			cacheSize.addAndGet(valueSize);
    
    			putSuccessfully = true;
    		}
    
       //获取bitMap的大小
        protected abstract int getSize(Bitmap value);
        //模板方法,由对应的子类来实现详细的删除策略
        protected abstract Bitmap removeNext();
    

    LargesetLimitedMemoryCache:

        该类为LimitedMemoryCache的子类,该类的目的是当超出缓存限制大小的时候删除缓存中最大的那个bitmap对象。

    该类实现了父类的两个抽象方法:getSize()和removeNext()来获取某个bitmap的大小和删除最大的那个bitMap对象。

      实现的原理: 该类加入了一个map变量,该map的key用来保存bitMap对象,而相应的value则保存bitmap的大小。

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

      详细的removeNext()实现:

     

          /**
    	 * 循环遍历valueSizes,并获取最大的那个bitmap,而且从map中删除之 
             返回的Bimmap对象交给父类的hardCache删除
    	 */
    	@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;
    	}
    
       //获取getSize的方法
       @Override
        protected int getSize(Bitmap value) {
            return value.getRowBytes() * value.getHeight();
        }
    
        @Override
        protected Reference<Bitmap> createReference(Bitmap value) {
            return new WeakReference<Bitmap>(value);
        }
    
    

    删除操作运行时机:调用父类put方法是运行

    <span style="font-size:12px;">@Override
    	public boolean put(String key, Bitmap value) {
    		if (super.put(key, value)) {//假设父类的方法为空。说明缓存的大小没有超出限制
    			valueSizes.put(value, getSize(value));
    			return true;
    		} else {//缓存的大小超出限制
    			return false;
    		}
    	}</span>

    FIFOLimitedMemoryCache :

    LimitedMomroyCache的子类,当当前缓存的大小超出限制的时候,会依据FIFO(先进先出)算法删除响应的bitmap缓存对象。该类用LinkedList来作为FIFO的实现方式,当超出缓存大小的时候,调用removeNext()来从缓存中删除首先增加进来的bitmap对象。对应的方法例如以下:

    实现原理:提供了一个LinkedList来保存bitmap对象

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

    详细的removeNext()方法实现:

    @Override
    	protected Bitmap removeNext() {
    		return queue.remove(0);
    	}
    
    	@Override
    	protected Reference<Bitmap> createReference(Bitmap value) {
    		return new WeakReference<Bitmap>(value);
    	}
    	
    	@Override
    	protected int getSize(Bitmap value) {
    		return value.getRowBytes() * value.getHeight();
    	}
    删除操作运行时机:调用父类put方法是运行

    @Override
    	public boolean put(String key, Bitmap value) {
    		if (super.put(key, value)) {//假设缓存没有超出范围
    			queue.add(value);//把bitmap放入队列
    			return true;
    		} else {//缓存超出范围
    			return false;
    		}
    	}


      LRULimitedMemoryCache:

    LimitedMemoryCache的子类。近期最久未使用缓存,当缓存大小超过sizeLimit限制的时候。就从缓存中删除近期最久未使用的bitmap缓存对象。

    实现原理:提供了一个LinkedHashMap来保存对象,实现LRU的效果

    /** Cache providing Least-Recently-Used logic */
    	private final Map<String, Bitmap> lruCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(INITIAL_CAPACITY, LOAD_FACTOR, true));
    详细的removeNext()方法实现:

    @Override
    	protected Bitmap removeNext() {
    		return queue.remove(0);
    	}
    
    	@Override
    	protected Reference<Bitmap> createReference(Bitmap value) {
    		return new WeakReference<Bitmap>(value);
    	}
    	
    	@Override
    	protected int getSize(Bitmap value) {
    		return value.getRowBytes() * value.getHeight();
    	}

    删除操作运行时机:调用父类put方法是运行

    @Override
    	public boolean put(String key, Bitmap value) {
    		if (super.put(key, value)) {//假设缓存没有超出范围
    			queue.add(value);//把bitmap放入队列
    			return true;
    		} else {//缓存超出范围
    			return false;
    		}
    	}

     UsingFreqLimitedMemoryCache:

    LimitedMemoryCache的子类,当缓存大小超出sizelimit的时候对最久未使用的bitmap对象进行删除(也就是说对使用次数最少的那个bitmap进行删除操作)

    实现原理:提供了一个hashMap。该map的key保存bitmap对象,而value则保存相应bitmap的使用次数

    private final Map<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());
    当调用get(string key)方法获取bitmap的时候,该bitmap的使用次数进行+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) {
    				//使用次数+1
    				usingCounts.put(value, usageCount + 1);
    			}
    		}
    		return value;
    	}

    详细的removeNext()实现方法:

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

    删除操作运行时机:调用父类put方法是运行

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

     LimitedAgeMemoryCache:

    对超出时间限制的缓存对象进行删除,该类的实现毕竟简单。详细代码例如以下:

    public class LimitedAgeMemoryCache implements MemoryCache {
    
    	private final MemoryCache cache;
    
    	private final long maxAge;
    	private final Map<String, Long> loadingDates = Collections.synchronizedMap(new HashMap<String, Long>());
    
    	/**
    	 * @param cache  Wrapped memory cache
    	 * @param maxAge Max object age <b>(in seconds)</b>. 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 void remove(String key) {
    		cache.remove(key);
    		loadingDates.remove(key);
    	}
    
    	@Override
    	public Collection<String> keys() {
    		return cache.keys();
    	}
    
    	@Override
    	public void clear() {
    		cache.clear();
    		loadingDates.clear();
    	}
    }

    FuzzyKeyMemoryCache:

    该缓存的作用就是假设缓存中的有一个key和要增加的keytemp相等。就从缓存中删除该key指向的bitmap对象,然后把新的key对象增加到缓存中去。

    详细的逻辑例如以下:

    	@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()) {
    				//推断缓存中相应的key是否存在,存在就删除
    				if (keyComparator.compare(key, cacheKey) == 0) {
    					keyToRemove = cacheKey;
    					break;
    				}
    			}
    			if (keyToRemove != null) {
    				cache.remove(keyToRemove);
    			}
    		}
    		return cache.put(key, value);
    	}

    LruMemoryCache

    又一个近期最久未使用缓存,在这里就不多说了,直接贴代码:

    @Override
    	public final boolean put(String key, Bitmap value) {		
    		synchronized (this) {
    			size += sizeOf(key, value);
    			Bitmap previous = map.put(key, value);
    			if (previous != null) {
    				size -= sizeOf(key, previous);
    			}
    		}
                  //缓存瘦身,把近期最久未使用的bitMap删除
    		trimToSize(maxSize);
    		return true;
    	}
    	private void trimToSize(int maxSize) {
    		while (true) {
    			String key;
    			Bitmap value;
    		        synchronized (this) {
    				
    				Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next();
    				if (toEvict == null) {
    					break;
    				}
    				key = toEvict.getKey();
    				value = toEvict.getValue();
    				map.remove(key);
    				size -= sizeOf(key, value);
    			}
    		}
    	}
    




  • 相关阅读:
    js 常见业务数据数组转换操作 时间复杂度降级O(n)的尝试
    【20220226】连岳摘抄
    【20220227】连岳摘抄
    【20220301】连岳摘抄
    【20220225】连岳摘抄
    【20220228】连岳摘抄
    【20220224】事情还是要乐观对待
    Atcoder Beginner Contest 208 F Cumulative Sum(拉格朗日插值)
    Solution 「CF 1622F」Quadratic Set
    Solution 「CF 923F」Public Service
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/7070803.html
Copyright © 2020-2023  润新知