这段时间在研究Universal-Image-Loader 这个图片处理开源框架,这里主要分析一下它的LRU(Least Resently Used,最近最少使用算法)内存缓存的实现。 
在UIL它提供的默认缓存类是LruMemoryCache,在它类上面有如下一段注释:

/**
* A cache that holds strong references to a limited number of Bitmaps. Each time a Bitmap is accessed, it is moved to
* the head of a queue. When a Bitmap is added to a full cache, the Bitmap at the end of that queue is evicted and may become eligible for garbage collection.<br />
* <b>NOTE:</b> This cache uses only strong references for stored Bitmaps.
*/

说明该缓存存储的是强引用的Bitmap对象,同时每当一个bitmap被访问之后,它就会被放到队列的头部,当队列满了需要删除元素时,就会删除队尾的元素,让它变成可以被垃圾回收器回收的对象。 
在LruMemoryCache中声明了三个全局变量:

private final LinkedHashMap<String, Bitmap> map;//存放对象的map容器
private final int maxSize; //缓存设定的最大值
/** Size of this cache in bytes */
private int size; //缓存中已经占有的大小

它的构造数也同样简单:

public LruMemoryCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);
}

这里传进来的maxSize参数在默认的情况下是程序进程占用内存总数的八分之一,单位是Byte。 
根据Key值获取对应的bitmap对象,代码超简单:

/**
* Returns the Bitmap for {@code key} if it exists in the cache. If a Bitmap was returned, it is moved to the head
* of the queue. This returns null if a Bitmap is not cached.
*/
@Override
public final Bitmap get(String key) {
if (key == null) {
throw new NullPointerException("key == null");
} synchronized (this) {
return map.get(key);
}
}

存储bitmap对象:

@Override
public final boolean put(String key, Bitmap value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
} synchronized (this) {
size += sizeOf(key, value); //调用sizeOf这个函数获得该bitmap对象的占用内存的大小,并且让缓存总数增加
Bitmap previous = map.put(key, value);//这里就是把对象放入容器中的最核心的一句代码,如果容器中已经有了此元素,则返回该元素的value值,否则返回空
if (previous != null) {
size -= sizeOf(key, previous);//如果容器中已经有了此元素,则需要把增加的数量减掉
}
} trimToSize(maxSize); //此函数计算是否超出最大限量,是则删除队尾元素
return true;
}

这里涉及到两个函数: 
获取图片大小的函数

private int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}

保证缓存内存量不超过设定的最大值

private void trimToSize(int maxSize) {
while (true) {
String key;
Bitmap value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");
} if (size <= maxSize || map.isEmpty()) {
break;
} 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);
}
}
}

此外,该类还有一个移除特定key的元素的方法:

/** Removes the entry for {@code key} if it exists. */
@Override
public final Bitmap remove(String key) {
if (key == null) {
throw new NullPointerException("key == null");
} synchronized (this) {
Bitmap previous = map.remove(key);
if (previous != null) {
size -= sizeOf(key, previous);
}
return previous;
}
}

至此整个缓存类就已经解析完了,你会发现其实代码超简单的,其中一个最重要的东西就是存放键值对的容器–LinkedHashMap。LinkedHashMap实现了Map接口,并且具有链表的特性,即有可预知的迭代顺序。通常在默认的情况下,该集合的迭代顺序是按照插入元素的顺序,先插入的元素在队尾,最后插入的在头部;然而当我们调用LinkedHashMap的构造函数LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) ,并传入accessOrder的值为true时,LinkedHashMap就会按照访问先后的顺序迭代,最近被访问的放在队头,最迟访问的在队尾。正是因为这个特性,LinkedHashMap很适合被用来作为LRU缓存的容器。因此有了LinkedHashMap这个神器,我们完全可以仿照UIL的缓存类构建自己的缓存!

Image-Loader LruMemoryCache的更多相关文章

  1. universal image loader自己使用的一些感受

    1.全局入口的Application定义初始化: ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Build ...

  2. Android中Universal Image Loader开源框架的简单使用

    UIL (Universal Image Loader)aims to provide a powerful, flexible and highly customizable instrument ...

  3. universal image loader在listview/gridview中滚动时重复加载图片的问题及解决方法

    在listview/gridview中使用UIL来display每个item的图片,当图片数量较多需要滑动滚动时会出现卡顿,而且加载过的图片再次上翻后依然会重复加载(显示设置好的加载中图片) 最近在使 ...

  4. 【Android应用开发】 Universal Image Loader ( 使用简介 | 示例代码解析 )

    作者 : 韩曙亮 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/50824912 相关地址介绍 : -- Universal I ...

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

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

  6. webpack入门教程之初识loader(二)

    上一节我们学习了webpack的安装和编译,这一节我们来一起学习webpack的加载器和配置文件. 要想让网页看起来绚丽多彩,那么css就是必不可少的一份子.如果想要在应用中增加一个css文件,那么w ...

  7. 简单实用的进度条加载组件loader.js

    本文提供一个简单的方法实现一个流程的进度条加载效果,以便在页面中可以通过它来更好地反馈耗时任务的完成进度.要实现这个功能,首先要考虑怎样实现一个静态的进度条效果,类似下面这样的: 这个倒是比较简单,两 ...

  8. 怎样写一个webpack loader

    div{display:table-cell;vertical-align:middle}#crayon-theme-info .content *{float:left}#crayon-theme- ...

  9. 异常:java.lang.LinkageError: loader constraint violation: when resolving interface method

    异常:java.lang.LinkageError: loader constraint violation: when resolving interface method "javax. ...

  10. ClassNotFoundException: org.apache.catalina.loader.DevLoader 自己摸索,丰衣足食

    使用tomcat插件时遇到的问题: ClassNotFoundException: org.apache.catalina.loader.DevLoader 解决方案: 参考了许多文章,对我自己的目录 ...

随机推荐

  1. [洛谷P1169] [ZJOI2007] 棋盘制作 解题报告(悬线法+最大正方形)

    题目描述 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个 8×8 大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳. 而我 ...

  2. Svn中的tag标签的用法和意义

    使用场景: 假如你的项目的某个版本已经完成测试开发.测试并已经上线,接下来街道新的需求,新项目开发需要修改多个文件的代码,当需求已经开发一段时间的时候,突然接到用户和测试人员的反馈,项目中某个重大的b ...

  3. jqueryEasyUI form表单提交的一个困惑

    今天用到了jqueryEasyUI的form表单做一个增加操作的提交,想打开调试(用的是火狐)看看传的参数,但是怎么也看不到form表单提交的http请求?而且还会发送一个另外的请求! 在页面加载时, ...

  4. ECNUOJ 2150 完美的拯救

    完美的拯救 Time Limit:1000MS Memory Limit:65536KBTotal Submit:147 Accepted:50 Description  一只可怜的蚂蚁被万恶的魔术师 ...

  5. dynamic_cast与能力查询

    在C++里面,dynamic_cast 通常用于横向转换,而不是向上或者向下的转换. 这个常常用于检查某个实例,是否实现了某个接口类,那么就把这个实例,用dynamic_cast来转换成这个接口类的实 ...

  6. [Recompose] Pass a React Prop to a Stream in RxJS

    When you declare your Component and Props in JSX, you can pass those props along to your RxJS stream ...

  7. HNU13303 Counting substhreengs(递推)

    题目:http://acm.hnu.cn/online/? action=problem&type=show&id=13303&courseid=0 题意:给你一个字符串,由数 ...

  8. POJ 1611 The Suspects 并查集 Union Find

    本题也是个标准的并查集题解. 操作完并查集之后,就是要找和0节点在同一个集合的元素有多少. 注意这个操作,须要先找到0的父母节点.然后查找有多少个节点的额父母节点和0的父母节点同样. 这个时候须要对每 ...

  9. JAVA并发--volatile

    学过计算机组成原理的一定知道,为了解决内存速度跟不上CPU速度这个问题,在CPU的设计中加入了缓存机制,缓存的速度介于CPU和主存之间.在进行运算的时候,CPU将需要的数据映射一份在缓存中,然后直接操 ...

  10. Container详解

    Container是一个拥有绘制.定位.调整大小的widget. padding和margin padding和margin分别设置Container的内边距和外边距.可取值包括下面四个: EdgeI ...