珍惜作者劳动成果,如需转载,请注明出处。 
http://blog.csdn.net/zhengzechuan91/article/details/50292871

Universal-Image-Loader 是一个优秀的图片加载开源项目,Github地址在 (Github地址) ,很多童鞋都在自己的项目中用到了。优秀的项目从来都是把简单留给开发者,把复杂封装在框架内部。ImageLoader作为Github上Star数过万的项目,备受开发者青睐,所以我们有必要搞清楚它的内部实现。

在上一篇博客中我们分析了ImageLoader框架的整体实现原理,还没有看过的直接到 深入解析开源项目之ImageLoader(一)框架篇 。


ImageLoader之内存缓存篇

项目截图:

由上图我们可以看出:

MemoryCache

package com.nostra13.universalimageloader.cache.memory;
import android.graphics.Bitmap;
import java.util.Collection;
public interface MemoryCache {
boolean put(String key, Bitmap value); Bitmap get(String key); Bitmap remove(String key); Collection<String> keys(); void clear();
}

BaseMemoryCache,LimitedAgeMemoryCache,LruMemoryCache,FuzzyKeyMemoryCache

public abstract class BaseMemoryCache implements MemoryCache {

    private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>());

    @Override
public Bitmap get(String key) {
Bitmap result = null;
Reference<Bitmap> reference = softMap.get(key);
if (reference != null) {
result = reference.get();
}
return result;
} @Override
public boolean put(String key, Bitmap value) {
softMap.put(key, createReference(value));
return true;
} @Override
public Bitmap remove(String key) {
Reference<Bitmap> bmpRef = softMap.remove(key);
return bmpRef == null ? null : bmpRef.get();
} @Override
public Collection<String> keys() {
synchronized (softMap) {
return new HashSet<String>(softMap.keySet());
}
} @Override
public void clear() {
softMap.clear();
} protected abstract Reference<Bitmap> createReference(Bitmap value);
}
public class LimitedAgeMemoryCache implements MemoryCache {//也是对MemoryCache的装饰

    private final MemoryCache cache;

    private final long maxAge;
private final Map<String, Long> loadingDates = Collections.synchronizedMap(new HashMap<String, Long>()); 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;
}

  //对MemeryCache的get(String key)做了加强处理:当我们在获取内存Cache中的Bitmap时,如果超过最大存活时间则不返回
@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 Bitmap remove(String key) {
loadingDates.remove(key);
return cache.remove(key);
} @Override
public Collection<String> keys() {
return cache.keys();
} @Override
public void clear() {
cache.clear();
loadingDates.clear();
}
}
//开源框架默认的内存缓存类,缓存的是bitmap的强引用,
public class LruMemoryCache implements MemoryCache { private final LinkedHashMap<String, Bitmap> map;
//缓存设定的最大值,maxSize 默认的情况下是程序进程占用内存总数的八分之一,单位是Byte。
private final int maxSize;
//** 缓存中已经占有的大小
private int size; public LruMemoryCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
     //true表示排序的顺序是从最远使用到最近使用,而返回false顺序则为插入时的顺序。
this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);
} @Override
public final Bitmap get(String key) {
if (key == null) {
throw new NullPointerException("key == null");
} synchronized (this) {
return map.get(key);
}
} /** Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue. */
@Override
public final boolean put(String key, Bitmap value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
} synchronized (this) {
//调用sizeOf这个函数获得该bitmap对象的占用内存的大小,并且让缓存总数增加
size += sizeOf(key, value);
//这里就是把对象放入容器中的最核心的一句代码,put()方法如果容器中已经有了此元素,则返回该元素的value值,否则添加进去并返回空
Bitmap previous = map.put(key, value);
if (previous != null) {
//如果容器中已经有了此元素,则需要把增加的数量减掉
size -= sizeOf(key, previous);
}
}
//此函数计算是否超出最大限量,是则删除队尾元素
trimToSize(maxSize);
return true;
} //删除最先加入的元素,移除最远使用的Bitmap
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);
}
}
} @Override
public final Bitmap remove(String key) {
if (key == null) {
throw new NullPointerException("key == null");
}
    //map实例化时并不是线程安全的,所以在所有的操作中都有同步锁。
synchronized (this) {
      //存在则返回该Bitmap,不存在返回null
Bitmap previous = map.remove(key);
if (previous != null) {
          ////如果移除的Bitmap存在
size -= sizeOf(key, previous);
}
return previous;
}
} @Override
public Collection<String> keys() {
synchronized (this) {
return new HashSet<String>(map.keySet());
}
} @Override
public void clear() {
trimToSize(-1); // -1 will evict 0-sized elements
} private int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
} @Override
public synchronized final String toString() {
return String.format("LruCache[maxSize=%d]", maxSize);
}
}
public class FuzzyKeyMemoryCache implements MemoryCache {//对MemoryCache的装饰

    private final MemoryCache cache;
private final Comparator<String> keyComparator; public FuzzyKeyMemoryCache(MemoryCache cache, Comparator<String> keyComparator) {
this.cache = cache;
this.keyComparator = keyComparator;
}

/*对MemoryCache的put(String key, Bitmap value)方法进行加强处理:先移除key相同的Bitmap,再添加新的key对应的Bitmap*/
@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()) {
if (keyComparator.compare(key, cacheKey) == 0) {
keyToRemove = cacheKey;
break;
}
}
if (keyToRemove != null) {
cache.remove(keyToRemove);
}
}
return cache.put(key, value);
} @Override
public Bitmap get(String key) {
return cache.get(key);
} @Override
public Bitmap remove(String key) {
return cache.remove(key);
} @Override
public void clear() {
cache.clear();
} @Override
public Collection<String> keys() {
return cache.keys();
}
}

LimitedMemoryCache,WeakMemoryCache

//重写LimitedMemoryCache主要是来实现removeNext()方法,以指定超过内存最大限定后移除Bitmap的规则。
public abstract class LimitedMemoryCache extends BaseMemoryCache { private static final int MAX_NORMAL_CACHE_SIZE_IN_MB = 16;
private static final int MAX_NORMAL_CACHE_SIZE = MAX_NORMAL_CACHE_SIZE_IN_MB * 1024 * 1024; private final int sizeLimit;//第2层最大缓存大小16M:多个线程只会读不会写 private final AtomicInteger cacheSize;//当前缓存的大小,原子操作:多个线程会对这个变量进行写 //强引用有引用变量指向时永远不会被垃圾回收。即使内存不足的时候宁愿报OOM也不被垃圾回收器回收,我们new的对象都是强引用
private final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>()); /** @param sizeLimit Maximum size for cache (in bytes) */
public LimitedMemoryCache(int sizeLimit) {
this.sizeLimit = sizeLimit;
cacheSize = new AtomicInteger();
if (sizeLimit > MAX_NORMAL_CACHE_SIZE) {
L.w("You set too large memory cache size (more than %1$d Mb)", MAX_NORMAL_CACHE_SIZE_IN_MB);
}
} @Override
public boolean put(String key, Bitmap value) {
boolean putSuccessfully = false;
// Try to add value to hard cache
int valueSize = getSize(value);
int sizeLimit = getSizeLimit();
int curCacheSize = cacheSize.get();
if (valueSize < sizeLimit) {//如果一个图片大于第2层最大值,则不用进行移除加入第2层了 while (curCacheSize + valueSize > sizeLimit) {//小于最大值加入第二层,
Bitmap removedValue = removeNext();//超过第二层最大值时4种移除第2层3层策略,第一层不移除
if (hardCache.remove(removedValue)) {
curCacheSize = cacheSize.addAndGet(-getSize(removedValue));
}
}
hardCache.add(value);
cacheSize.addAndGet(valueSize); putSuccessfully = true;
}
// Add value to soft cache
super.put(key, value);//加入第一层
return putSuccessfully;
} @Override
public Bitmap remove(String key) {
Bitmap value = super.get(key);//第1层
if (value != null) {//第1层有
if (hardCache.remove(value)) {//第2层删除
cacheSize.addAndGet(-getSize(value));
}
}
return super.remove(key);//第1层删除,返回第1层删除的
} @Override
public void clear() {
hardCache.clear();//第2层删除
cacheSize.set(0);
super.clear();//第1层删除
} protected int getSizeLimit() {
return sizeLimit;
} protected abstract int getSize(Bitmap value); protected abstract Bitmap removeNext();
}
//这个类缓存bitmap的总大小没有限制,唯一不足的地方就是不稳定,缓存的图片容易被回收掉
public class WeakMemoryCache extends BaseMemoryCache {
@Override
protected Reference<Bitmap> createReference(Bitmap value) {
//弱引用通过weakReference类来实现,如果垃圾回收器扫描到有着WeakReference的对象,就会将其回收释放内存
return new WeakReference<Bitmap>(value);
}
}

FIFOLimitedMemoryCache,LargestLimitedMemoryCache,LRULimitedMemoryCache,UsingFreqLimitedMemoryCache

public class FIFOLimitedMemoryCache extends LimitedMemoryCache {

    private final List<Bitmap> queue = Collections.synchronizedList(new LinkedList<Bitmap>());

    public FIFOLimitedMemoryCache(int sizeLimit) {
super(sizeLimit);//设置第2层最大值
} @Override
public boolean put(String key, Bitmap value) {
if (super.put(key, value)) {//第2层加了,1,3层也要加
queue.add(value);
return true;
} else {//超过第2层总共最大值,第2,3层不添加,只加到第一层
return false;
}
} @Override
public Bitmap remove(String key) {
Bitmap value = super.get(key);//获取第1层软引用缓存有没有
if (value != null) {//第1层有
queue.remove(value);//第3层删除
}
return super.remove(key);//第2层
} @Override
public void clear() {
queue.clear();//第3层删除
super.clear();//第2层
} @Override
protected int getSize(Bitmap value) {
return value.getRowBytes() * value.getHeight();
} @Override
protected Bitmap removeNext() {
return queue.remove(0);//删除第3层第1个
} @Override
protected Reference<Bitmap> createReference(Bitmap value) {
return new WeakReference<Bitmap>(value);
}
}
public class LargestLimitedMemoryCache extends LimitedMemoryCache {

    private final Map<Bitmap, Integer> valueSizes = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());

    public LargestLimitedMemoryCache(int sizeLimit) {
super(sizeLimit);//设置第2层最大值
} @Override
public boolean put(String key, Bitmap value) {
if (super.put(key, value)) {//第2层加了,1,3层也要加。
valueSizes.put(value, getSize(value));
return true;
} else {//第2层加不进去,3层不加,只加第一层
return false;
}
} @Override
public Bitmap remove(String key) {
Bitmap value = super.get(key);//第一层
if (value != null) {//第一层有
valueSizes.remove(value);//移除第三层
}
return super.remove(key);
} @Override
public void clear() {
valueSizes.clear();
super.clear();
} @Override
protected int getSize(Bitmap value) {
return value.getRowBytes() * value.getHeight();
} @Override
protected Bitmap removeNext() {//删除最大的bitmap对象
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;
} @Override
protected Reference<Bitmap> createReference(Bitmap value) {
return new WeakReference<Bitmap>(value);
}
}
public class LRULimitedMemoryCache extends LimitedMemoryCache {

    private static final int INITIAL_CAPACITY = 10;
private static final float LOAD_FACTOR = 1.1f; private final Map<String, Bitmap> lruCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(INITIAL_CAPACITY, LOAD_FACTOR, true)); public LRULimitedMemoryCache(int maxSize) {
super(maxSize);
} @Override
public boolean put(String key, Bitmap value) {
if (super.put(key, value)) {
lruCache.put(key, value);
return true;
} else {
return false;
}
} @Override
public Bitmap get(String key) {
lruCache.get(key); // call "get" for LRU logic
return super.get(key);
} @Override
public Bitmap remove(String key) {
lruCache.remove(key);
return super.remove(key);
} @Override
public void clear() {
lruCache.clear();
super.clear();
} @Override
protected int getSize(Bitmap value) {
return value.getRowBytes() * value.getHeight();
} @Override
protected Bitmap removeNext() {
Bitmap mostLongUsedValue = null;
synchronized (lruCache) {
Iterator<Entry<String, Bitmap>> it = lruCache.entrySet().iterator();
if (it.hasNext()) {
Entry<String, Bitmap> entry = it.next();
mostLongUsedValue = entry.getValue();
it.remove();
}
}
return mostLongUsedValue;
} @Override
protected Reference<Bitmap> createReference(Bitmap value) {
return new WeakReference<Bitmap>(value);
}
}
public class UsingFreqLimitedMemoryCache extends LimitedMemoryCache {

    private final Map<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());

    public UsingFreqLimitedMemoryCache(int sizeLimit) {
super(sizeLimit);
} @Override
public boolean put(String key, Bitmap value) {
if (super.put(key, value)) {
usingCounts.put(value, 0);
return true;
} else {
return false;
}
} @Override
public Bitmap get(String key) {//读取一次加1
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) {
usingCounts.put(value, usageCount + 1);
}
}
return value;
} @Override
public Bitmap remove(String key) {
Bitmap value = super.get(key);
if (value != null) {
usingCounts.remove(value);
}
return super.remove(key);
} @Override
public void clear() {
usingCounts.clear();
super.clear();
} @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);
}
}

深入解析开源项目之Universal-Image-Loader(二)内存---缓存篇的更多相关文章

  1. 开源项目MultiChoiceAdapter详解(二)——MultiChoiceArrayAdapter的使用

    MultiChoiceArrayAdapter其实就是可以多选的ArrayAdapter了,ArrayAdpter我们已经很熟悉了.MultiChoiceArrayAdapter这个类是抽象类,所以使 ...

  2. 开源项目SMSS开发指南(二)——基于libevent的线程池

    libevent是一套轻量级的网络库,基于事件驱动开发.能够实现多线程的多路复用和注册事件响应.本文将介绍libevent的基本功能以及如何利用libevent开发一个线程池. 一. 使用指南 监听服 ...

  3. 开源项目PullToRefresh详解(二)——PullToRefreshGridView

    这里介绍的是PullToRefreshGridView的使用方法,和之前的PullToRefreshListView方法如出一辙,因为这个开源项目模块化很棒,所以很容易实现.等于说我们可以按照之前使用 ...

  4. 深入解析开源项目之Universal-Image-Loader(二)硬盘---缓存篇

    文件命名: FileNameGenerator,HashCodeFileNameGenerator,Md5FileNameGenerator package com.nostra13.universa ...

  5. Diycode开源项目 如何解决InputMethodManager造成的内存泄漏问题

    1.内存泄漏的状况及原因 1.1.利用LeakCanary查看内存泄漏的状况 1.2.内存泄漏怎么产生的呢? InputMethodManager.mServicedView持有一个最后聚焦View的 ...

  6. .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现

    本篇我将带着大家一起来对Dapper进行下封装并实现基本的增删改查.分页操作的同步异步方法的实现(已实现MSSQL,MySql,PgSQL).同时我们再实现一下仓储层的代码生成器,这样的话,我们只需要 ...

  7. apache基金会开源项目简介

    apache基金会开源项目简介   项目名称 描述 HTTP Server 互联网上首屈一指的HTTP服务器 Abdera Apache  Abdera项目的目标是建立一个功能完备,高效能的IETF ...

  8. 值得研究的J2EE开源项目推荐

    导读:笔者在学习J2EE的过程中发现了一些很有用,而且很值得学习的开源项目,在此推荐给大家. 关键词:J2EE 开源项目 J2SE JBoss SOA EJB   这篇文章写在我研究J2SE.J2EE ...

  9. 可删除超炫&amp;多种特效的Card视图(改造自cardsui-for-android开源项目),提供DEMO下载

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990).谢谢支持!        实例Demo下载地址在本文最后 简介 这个Demo主要是使用了cardsui ...

随机推荐

  1. POJ 3662 二分+Dijkstra

    题意: 思路: 二分+Disjktra 二分一个值 如果某条边的边权比它小,则连上边权为0的边,否则连上边权为1的边 最后的d[n]就是最小要免费连接多少电话线. //By SiriusRen #in ...

  2. Storm框架基础(一)

    * Storm框架基础(一) Storm简述 如果你了解过SparkStreaming,那么Storm就可以类比着入门,在此我们可以先做一个简单的比较:  在SparkStreaming中: 我们曾尝 ...

  3. CUDA还未产出,又要出北洋多元统计习题集

    其实目前是自己摸清了一个套路.genome realign的算法,以及CUDA的写法都已经有数了,前两天也弄完了关静的所有任务.但是今天关静早上一上来就宣布一个重磅消息:除了全学期的作业和期末论文,另 ...

  4. WebSocket handshake: Unexpected response code: 404

    在执行    http://www.cnblogs.com/best/p/5695570.html  提供的 websocket时候, 报错了 “WebSocket handshake: Unexpe ...

  5. 联想服务器thinkserver TS550 Raid5制作及winserver2012R2 安装过来

    一. 联想服务器thinkserver TS550 Raid5制作 1.开机后按ctrl+i  进入raid配置模式 2.选择“1”配置所需Raid模式(这次配的是raid5) 3.按提示确认后退出 ...

  6. BZOJ 3277/3473 广义后缀自动机

    说实话没啥难的. 建一棵广义后缀自动机,暴力自底向上更新即可. 时间复杂度非常玄学,但据说是可以过的. 要注意每个串中相同的子串的贡献是都要加进去的,开始因为这个被坑了好久 QAQ Code: #in ...

  7. 【Henu ACM Round#20 C】 Eevee

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 处理处所有的字符串可能的样子. 存在map里面就好. [代码] #include <bits/stdc++.h> usi ...

  8. 【Codeforces Round #422 (Div. 2) B】Crossword solving

    [题目链接]:http://codeforces.com/contest/822/problem/B [题意] 让你用s去匹配t,问你最少需要修改s中的多少个字符; 才能在t中匹配到s; [题解] O ...

  9. POJ3904 Sky Code【容斥原理】

    题目链接: http://poj.org/problem?id=3904 题目大意: 给你N个整数.从这N个数中选择4个数,使得这四个数的公约数为1.求满足条件的 四元组个数. 解题思路: 四个数的公 ...

  10. 设置UITableViewCell高度的问题

    有非常多时候.UITableViewCell每行的高度是不固定的,须要动态设置. UITableView有个代理方法, -(CGFloat)tableView:(UITableView *)table ...