这段时间在研究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. Word histogram

    Here is a program that reads a file and builds a histogram of the words in the file: process_file lo ...

  2. directshow 获取本地摄像头播放

    最近因为项目的需要,做了一个基本的获取本地笔记本摄像头并且播放的例子,因为网上的关于这部分的完整例子基本都没有,那我就上传一个吧,希望能够帮到需要学习视频的朋友. 另外也是为了纪念雷霄骅博士为音视频方 ...

  3. Flume 启动

    Configuration是Flume项目的入口程序了,当我们输入 bin/flume-ng agent --conf conf --conf-file conf/kafka1.properties ...

  4. 为Activity生成桌面快捷方式

    有时候如果想让我们的应用在桌面上创建多个快捷方式,我们可以在Manifest.xml文件中对相应的activity进行声明. <application android:icon="@d ...

  5. hiho1515 - 数据结构 并查集

    题目链接 小Hi的学校总共有N名学生,编号1-N.学校刚刚进行了一场全校的古诗文水平测验. 学校没有公布测验的成绩,所以小Hi只能得到一些小道消息,例如X号同学的分数比Y号同学的分数高S分. 小Hi想 ...

  6. php基础:define()定义常数函数

    define(); 常量类似变量,不同之处在于: 在设定以后,常量的值无法更改 常量名不需要开头的美元符号 ($) 作用域不影响对常量的访问 常量值只能是字符串或数字 <?php define( ...

  7. 细说ReactiveCocoa的冷信号与热信号(一)

    热信号:事件触发: 冷信号:订阅出发: 从本质上来说,是信号的存在和产生,是静态信号和动态信号的区别. 背景 ReactiveCocoa(简称RAC)是最初由GitHub团队开发的一套基于Cocoa的 ...

  8. How Javascript works (Javascript工作原理) (十四) 解析,语法抽象树及最小化解析时间的 5 条小技巧

    个人总结:读完这篇文章需要15分钟,文章介绍了抽象语法树与js引擎解析这些语法树的过程,提到了懒解析——即转换为AST的过程中不直接进入函数体解析,当这个函数体需要执行的时候才进行相应转换.(因为有的 ...

  9. [POI2008]POD-Subdivision of Kingdom(搜索+状压)

    题意 给定一个n个点的无向图,要求将点集分成大小相等的两个子集,使两个子集之间的边数最少 (n<=26) 题解 一开始想了半天DP发现不会,去看题解全是搜索. 所以发现C(1326)可以过我就写 ...

  10. java源码学习

    Collection List ArrayList LinkedList Vector Stack Set HashSet TreeSet Map HashMap TreeMap LinkedHash ...