前面的两篇博客写了文件缓存。如今说说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);@Overridepublic 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放入缓存@Overridepublic 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删除*/@Overrideprotected 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的方法@Overrideprotected int getSize(Bitmap value) {return value.getRowBytes() * value.getHeight();}@Overrideprotected Reference<Bitmap> createReference(Bitmap value) {return new WeakReference<Bitmap>(value);}

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

<span style="font-size:12px;">@Overridepublic 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()方法实现:

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

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

@Overridepublic 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()方法实现:

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

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

@Overridepublic 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操作

@Overridepublic Bitmap get(String key) {Bitmap value = super.get(key);// Increment usage count for value if value is contained in hardCaheif (value != null) {Integer usageCount = usingCounts.get(value);if (usageCount != null) {//使用次数+1usingCounts.put(value, usageCount + 1);}}return value;}

详细的removeNext()实现方法:

@Overrideprotected int getSize(Bitmap value) {return value.getRowBytes() * value.getHeight();}@Overrideprotected 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;}@Overrideprotected Reference<Bitmap> createReference(Bitmap value) {return new WeakReference<Bitmap>(value);}

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

@Overridepublic 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}@Overridepublic boolean put(String key, Bitmap value) {boolean putSuccesfully = cache.put(key, value);if (putSuccesfully) {loadingDates.put(key, System.currentTimeMillis());}return putSuccesfully;}@Overridepublic 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);}@Overridepublic void remove(String key) {cache.remove(key);loadingDates.remove(key);}@Overridepublic Collection<String> keys() {return cache.keys();}@Overridepublic void clear() {cache.clear();loadingDates.clear();}
}

FuzzyKeyMemoryCache:

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

详细的逻辑例如以下:

  @Overridepublic boolean put(String key, Bitmap value) {// Search equal key and remove this entrysynchronized (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:
又一个近期最久未使用缓存,在这里就不多说了,直接贴代码:

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

转载于:https://www.cnblogs.com/cxchanpin/p/7070803.html

Android-Universal-Image-Loader学习笔记(3)--内存缓存相关推荐

  1. android universal image loader 缓冲原理详解

    1. 功能介绍 1.1 Android Universal Image Loader Android Universal Image Loader 是一个强大的.可高度定制的图片缓存,本文简称为UIL ...

  2. Redis运维和开发学习笔记(7) 内存管理和过期策略

    Redis运维和开发学习笔记(7) 内存管理和过期策略 文章目录 Redis运维和开发学习笔记(7) 内存管理和过期策略 内存回收策略 惰性删除 定时任务删除 maxmemory 过期策略allkey ...

  3. 【JVM学习笔记】内存回收与内存回收算法 就哪些地方需要回收、什么时候回收、如何回收三个问题进行分析和说明

    目录 一.相关名词解释 垃圾收集常用名词 二.哪些地方需要回收 本地方法栈.虚拟机栈.程序计数器 方法区 Java堆 三.什么时候回收 1. 内存能否被回收 内存中的引用类型 引用计数算法 可达性分析 ...

  4. Android(java)学习笔记176: 远程服务的应用场景(移动支付案例)

    一. 移动支付:       用户需要在移动终端提交账号.密码以及金额等数据 到 远端服务器.然后远端服务器匹配这些信息,进行逻辑判断,进而完成交易,返回交易成功或失败的信息给移动终端.用户提交账号. ...

  5. Android日常开发 - FlexboxLayout学习笔记

    Android日常开发 - FlexboxLayout学习笔记 Android日常开发使用FlexboxLayout实现流式布局的效果,FlexboxLayout与h5中的flex使用十分相似,都是将 ...

  6. 深入理解Java虚拟机(第3版)学习笔记——JAVA内存区域(超详细)

    深入理解Java虚拟机(第3版)学习笔记--JAVA内存区域(超详细) 运行时数据区域 程序计数器 java虚拟机栈 本地方法栈 java堆 方法区 运行时常量池 直接内存 对象的创建 对象的内存布局 ...

  7. Android Studio下载搭建学习笔记01

    Android Studio下载搭建学习笔记01 下载Android Studio 安装Android Studio 进入安装向导 选择安装组件 选择安装位置 选择文件菜单 等待安装 启动并配置And ...

  8. 我的Android进阶之旅------gt;Android中编解码学习笔记

    编解码学习笔记(一):基本概念 媒体业务是网络的主要业务之间.尤其移动互联网业务的兴起,在运营商和应用开发商中,媒体业务份量极重,其中媒体的编解码服务涉及需求分析.应用开发.释放license收费等等 ...

  9. [Android]Android P(9) WIFI学习笔记 - HAL (1)

    目录 前文回顾 前言 入口 WifiNative 初始化 打开WIFI IWifiChip IWifiCond ISupplicant 前文回顾 WIFI学习笔记 - Framework (1) WI ...

  10. Android的LMK机制学习笔记

    初识Android的LMK机制 一.文章背景 1.1 LMK中kill进程的关键log(原生系统):![LMK中kill进程的关键log](https://img-blog.csdnimg.cn/78 ...

最新文章

  1. lwip可以用于发udp_LWIPUDP一对多
  2. Vue 中多个元素、组件的过渡,及列表过渡
  3. qt同时连接oracle和mysql_QT连接Oracle和Mysql的详细步骤,已成功~!
  4. 诗与远方:无题(八十五)- 无字天书
  5. Hibernate学习笔记--映射配置文件详解
  6. XSS-Game level 5
  7. paip.php and or 语句用法作用
  8. 为什么年龄大了近视还增加_都是做近视手术,为什么价格区别这么大?
  9. 教你Java 代码性能优化小妙招,速速来看
  10. JAVA ME游戏----个人移植:9688雷霆战机
  11. altium designer2020安装教程
  12. Pyinstaller打包成使用了pyonnet包的exe时报错System.IO.FileNotFoundException:Unable to find assembly ‘XXX.dll‘。
  13. 推荐 5 个精选公众号
  14. Python语法基础 三
  15. 全排列(从大到小排列)
  16. 相机响应曲线、ISO详解
  17. Go设置一个工作区打开多个项目
  18. Matlab中meshgrid的用法
  19. 功率放大器设计方案(包含原理图+PCB+BOM表)
  20. .pvr.ccz 与 png 格式 互转的解决方案

热门文章

  1. python编程狮题库答案_‎Python编程狮-零基础学Python dans l’App Store
  2. python 查找算法_python快速查找算法应用实例
  3. python 40位的数减个位数_Python——进制表示与转换
  4. php的变量都放在哪里,php变量一般放在哪个位置
  5. 【Makefile】
  6. 乐惠科技php面试题,程序员中的奇葩,使用php构建魔兽世界
  7. C vector详解
  8. oracle plsql异常,【Oracle篇】异常处理和PLSQL
  9. 获取客户端ip_代理IP工具能否解决反爬?
  10. css 竖行进度图_前端学习--汇集了大量 CSS 的使用和学习的示例代码