这段时间在研究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. 46. AngularJS所有版本下载

    转自:https://www.cnblogs.com/best/tag/Angular/ 官网下载:https://angularjs.org/ AngularJS所有版本下载:https://cod ...

  2. rsync同步操作命令

    在本地磁盘同步数据 将/home做个备份 # rsync -a --delete /home /backups -a 归档模式,表示以递归方式传输文件, -delete 删除那些接收端还有而发送端已经 ...

  3. [NOIP2015模拟10.27] [JZOJ4270] 魔道研究 解题报告(动态开点+权值线段树上二分)

    Description “我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力.”——<The Grimoire of Marisa>雾雨魔理 ...

  4. 使用regasm注册.net com组件出现不是有效的.net程序集的解决办法

    作者:朱金灿 来源:http://blog.csdn.net/clever101 在电脑上装有VS 2008和VS 2010.使用VS 2010编写了一个C# com组件:MyCom(基于.net f ...

  5. 范型在java中的应用

    根据泛型在java中的不同位置,大致可以分为类泛型.方法泛型和接口泛型.以下三个Demo基本展现三种泛型的用法,其中接口泛型又分两种情况描述.类泛型和方法泛型 import java.util.Arr ...

  6. 瞎折腾-CentOS 7.4 编译4.16.2版kernel 并安装

    CentOS 7.4下 原内核版本: 3.10.0-693.el7.x86_64 改后内核版本: 4.16.2 系统版本: CentOS-7-x86_64-Minimal-1708.iso 运行环境: ...

  7. next.js、nuxt.js等服务端渲染框架构建的项目部署到服务器,并用PM2守护程序

    前端渲染:vue.react等单页面项目应该这样子部署到服务器 貌似从前几年,前后端分离逐渐就开始流行起来,把一些渲染计算的工作抛向前端以便减轻服务端的压力,但为啥现在又开始流行在服务端渲染了呢?如v ...

  8. string.split 应用

    采用string.split将字符串依据分隔符,转换成字符串数组,生成的字符串数组中会包含空数组元素,需要通过StringSplitOptions.RemoveEmptyEntries参数选项去除. ...

  9. 【习题 8-18 UVA - 1619】Feel Good

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 用单调队列求出l[i]和r[i] 分别表示i的左边最近的大于a[i]的数的位置以及i右边最近的大于a[i]的数的位置. 则l[i]+ ...

  10. AndroidMainfest.xml具体解释——&lt;activity&gt;

    语法: <activity android:allowEmbedded=["true" | "false"] android:allowTaskRepar ...