前面的两篇博客写了文件缓存。如今说说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);
}
}
}

Android-Universal-Image-Loader学习笔记(3)--内存缓存的更多相关文章

  1. RHCA442学习笔记-Unit11内存缓存

      Unit 11 Memory Caches 内存缓存           学习目标:                 A. 使用内存来改善运行慢的子系统的服务时间.   11.1 Strategi ...

  2. Android(java)学习笔记160:Framework运行环境之 Android进程产生过程

    1.前面Android(java)学习笔记159提到Dalvik虚拟机启动初始化过程,就下来就是启动zygote进程: zygote进程是所有APK应用进程的父进程:每当执行一个Android应用程序 ...

  3. Android(java)学习笔记205:网易新闻RSS客户端应用编写逻辑过程

    1.我们的项目需求是编写一个新闻RSS浏览器,RSS(Really Simple Syndication)是一种描述和同步网站内容的格式,是使用最广泛的XML应用.RSS目前广泛用于网上新闻频道,bl ...

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

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

  5. LM3S之boot loader学习笔记-2

    LM3S之boot loader学习笔记-2 彭会锋 () 上一篇中介绍了bootloader的基础知识,对于bootloader的作用和如何编写bootloader也有了大概的了解了,这一篇主要讲解 ...

  6. Android(java)学习笔记103:Framework运行环境之 Android进程产生过程

    1. 前面Android(java)学习笔记159提到Dalvik虚拟机启动初始化过程,就下来就是启动zygote进程: zygote进程是所有APK应用进程的父进程:每当执行一个Android应用程 ...

  7. Android(java)学习笔记148:网易新闻RSS客户端应用编写逻辑过程

    1.我们的项目需求是编写一个新闻RSS浏览器,RSS(Really Simple Syndication)是一种描述和同步网站内容的格式,是使用最广泛的XML应用.RSS目前广泛用于网上新闻频道,bl ...

  8. Android自动化测试之Monkeyrunner学习笔记(一)

    Android自动化测试之Monkeyrunner学习笔记(一) 因项目需要,开始研究Android自动化测试方法,对其中的一些工具.方法和框架做了一些简单的整理,其中包括Monkey.Monkeyr ...

  9. Android(java)学习笔记267:Android线程池形态

    1. 线程池简介  多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.     假设一个服务器完成一项任务所需时间为:T1 创建线程时间, ...

  10. Android(java)学习笔记207:开源项目使用之gif view

    1. 由于android没有自带的gif动画,我在Android(java)学习笔记198:Android下的帧动画(Drawable Animation) 播客中提到可以使用AnimationVie ...

随机推荐

  1. ISAM Indexed Sequential Access Method 索引顺序存取方法

    ISAM Indexed Sequential Access Method 索引顺序存取方法 学习了:https://baike.baidu.com/item/ISAM/3013855 是IBM发展起 ...

  2. Android 自己定义View学习(2)

    上一篇学习了基本使用方法,今天学一下略微复杂一点的.先看一下效果图 为了完毕上面的效果还是要用到上一期开头的四步 1,属性应该要有颜色,要有速度 <?xml version="1.0& ...

  3. cocos2d-x 3.0 经常使用对象的创建方式

    cocos2d-x 3.0 中全部对象差点儿都能够用create函数来创建,其它的创建方式也是有create函数衍生. 以下来介绍下create函数创建一般对象的方法,省得开发中常常忘记啥的. 1.精 ...

  4. MySql 基础学习笔记 1——概述与基本数据类型: 整型: 1)TINYINT 2)SMALLINT 3) MEDIUMINT 4)INT 5)BIGINT 主要是大小的差别 图 浮点型:命令

    一.CMD中经常使用mysql相关命令 mysql -D, --database=name  //打开数据库 --delimiter=name  //指定分隔符 -h, --host=name  // ...

  5. DB-MySQL:MySQL GROUP BY

    ylbtech-DB-MySQL:MySQL GROUP BY 1.返回顶部 1. MySQL GROUP BY 语句 GROUP BY 语句根据一个或多个列对结果集进行分组. 在分组的列上我们可以使 ...

  6. Hessian实例

    简述Hessian Hessian是一个由Caucho Technology开发的轻量级RPC框架,由于它使用二进制RPC协议,所以它更快.更简单,很适合于发送二进制数据(访问官网): 在进行基于He ...

  7. Js radio

    <input type="radio" name="sex" value="1" />男 <input type=&quo ...

  8. 格式化日期字符串 FormatSettings使用

    如果 你想要得到 YYYY-MM/DD 这样的字符串 你肯定说这太简单了  直接 ShowMessage(FormatDateTime('YYYY-MM/DD',now)); 运行结果 YYYY-MM ...

  9. 用Latex做介绍自己和团队科研的网页

    最近实验室师妹用网上的一些模板改了改做了几个网页.感觉还可以.但是实际上总觉得好像和韩家炜.周志华他们的页面差点什么. 最近找论文时发现奥地利的hornik老先生页面居然latex做的,然后找到了下面 ...

  10. 从Dinnr失败看产品市场可行性认知有哪些不足

    对所有互联网创始人来说,在实际创业之前「验证idea的市场可行性」是至关重要的事情,许多人会用访谈的方式询问潜在顾客的意见,本期的就已Dinnr为案例,当初用户访谈结果乐观,实际上线后却无人买单,创办 ...