Android图片加载

转载请注明出处:[作者CJstar]http://blog.csdn.net/cj_star/article/details/48526867

为什么要使用内存缓存
内存缓存:
内存缓存是指将已经赋值的对象保存在内存中,当再次使用的时候直接去内存读取,不再做重复的创建操作。

内存缓存的优势:
对象的重复使用,不再去创建对象,减少内存消耗,便于内存的集中管理。同时在需要读取数据库或者外存的时候,使用内存缓存将大大减少时间,提供程序的整体性能。

内存缓存的原理
JVM垃圾回收机制

JVM采用的是引用计数的机制,处理数据回收的问题。引用计数:即类被加载到内存以后,会在方法区,堆栈,以及程序计数器的地方分配相应的空间,同时对应产生一个引用计数器,专门计数对象被使用的情况。如果新的地方引用了对象,计数器就+1,引用销毁的时候计数器-1,当计数器为0的时候,对象被标记为可被回收。由于该机制不能处理互相引用的情况,加入了根搜索算法,解决互相引用时计数器始终>=1的情况。
引用的类型
强引用:

只要引用存在,垃圾回收器就不会回收。
如:
A a = new A();
B b = new B();
a.b = b;

这时候b属于a的强引用,只有a被回收后b才能被回收。

软引用:

软引用是非必须的引用,当内存不足时可被回收的 。
如:
Java
A a = new A();
SoftRefernece<A> softA = new SoftRefernece<A>(a);
softA.get();//取A的值

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。


弱引用:

第二次垃圾回收时回收

Java
A a = new A();
WeakReference<A> weakA = new WeakReference<A>(a);
weakA.get();//获取A对象
weakA.isEnQueued();//返回垃圾回收器是否将其标记为可回收。

软引用第一次垃圾回收器扫描到的时候不会马上回收,会把它标记为可回收资源,第二次JVM回收内存的时候如果a还未被引用过,内存将被回收,这时softA.get()返回值是null。这样的好处是a对象可以短暂被保存,但是每次用get方法取值时都需要判断对象是否为空!

虚引用:

每次JVM回收垃圾的时候都会被回收。
Java
A a = new A();
PhantomReference<A> phantomA = new PhantomReference<A>(a);
phantomA.get();//永远返回null
phantomA.isEnQueued();//返回内存中已删除

虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。

内存缓存的实现策略

Java
/**
* Created by CJstar on 15/9/2.
*/
public class LRUBitmapMemoryCache implements MemmoryCache<Bitmap> {

private static final String TAG = "LRUBitmapMemoryCache";

private MemoryCacheOptions options;
//强引用
private LruCache<String, Bitmap> mMemoryCache;
//软引用
private LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache;

/**
* Create a instance by default config
*/
public LRUBitmapMemoryCache() {
options = new MemoryCacheOptions.Builder()
.setmMaxCacheCount(DefaultConfig.MemoryCacheDefaultOptions.MAXCACHECOUNT)
.setmMaxCacheSize(DefaultConfig.MemoryCacheDefaultOptions.MAXCACHESIZE)
.setmUseCache(DefaultConfig.MemoryCacheDefaultOptions.USECACHE)
.build();
initializeCache();
}

/**
* set a options as you set
*
* @param defaultOptions
*/
@Override
public void setOptions(MemoryCacheOptions defaultOptions) {
this.options = defaultOptions;
}

private void initializeCache() {

if (options == null) {
throw new VinciException("LRUBitmapMemoryCache#options is null");
}

if (options.getmMaxCacheSize() == 0) {
throw new VinciException("LRUBitmapMemoryCache#max cache size is o");
}

if (options.getmMaxCacheCount() == 0) {
throw new VinciException("LRUBitmapMemoryCache#max cache count is o");
}

MLog.d(TAG, "maxSize:" + options.getmMaxCacheSize() + " maxCount:" + options.getmMaxCacheCount());
mMemoryCache = new LruCache<String, Bitmap>(options.getmMaxCacheSize()) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in kilobytes rather than
// number of items.
return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
}

@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
// TODO Auto-generated method stub
super.entryRemoved(evicted, key, oldValue, newValue);
if (oldValue != null) {
// the allocation is full, move bitmap to soft reference
mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));
testLog("entryRemoved to mSoftCache:" + key);
}

}
};

mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(
options.getmMaxCacheCount(), 0.75f, true) {
private static final long serialVersionUID = 6040103833179403725L;

@Override
protected boolean removeEldestEntry(
Entry<String, SoftReference<Bitmap>> eldest) {
if (size() > options.getmMaxCacheCount()) {
testLog("removeEldestEntry true");
return true;
}

testLog("removeEldestEntry full");
return false;
}
};
}

@Override
public Bitmap get(String key) {
testLog("get:" + key);

if (TextUtils.isEmpty(key)) {
return null;
}

Bitmap bitmap;

// get bitmap from mMemoryCache
synchronized (mMemoryCache) {
bitmap = mMemoryCache.get(key);

if (bitmap != null && !bitmap.isRecycled()) {
// LRU : refresh this bitmap position
mMemoryCache.remove(key);
mMemoryCache.put(key, bitmap);
testLog("get mMemoryCache");

return bitmap;
}

}

// get bitmap from mSoftCache
synchronized (mSoftCache) {
SoftReference<Bitmap> bitmapReference = mSoftCache.get(key);
if (bitmapReference != null) {
bitmap = bitmapReference.get();

if (bitmap != null && !bitmap.isRecycled()) {
// move bitmap to mSoftCache
mMemoryCache.put(key, bitmap);
mSoftCache.remove(key);
testLog("get mSoftCache");

return bitmap;

} else {
// is recycled
mSoftCache.remove(key);
}
}
}

return null;
}

@Override
public boolean isExist(String key) {
if (TextUtils.isEmpty(key)) {
return false;
}

Bitmap bitmap;

// get bitmap from mMemoryCache
synchronized (mMemoryCache) {
bitmap = mMemoryCache.get(key);
if (bitmap != null && !bitmap.isRecycled()) {
return true;
}
}

// get bitmap from mSoftCache
synchronized (mSoftCache) {
SoftReference<Bitmap> bitmapReference = mSoftCache.get(key);
if (bitmapReference != null) {
bitmap = bitmapReference.get();
if (bitmap != null && !bitmap.isRecycled()) {
return true;
}
}
}


return false;
}

@Override
public Bitmap remove(String key) {
// remove bitmap from mMemoryCache
Bitmap bitmap;
synchronized (mMemoryCache) {
bitmap = mMemoryCache.remove(key);
}

// remove bitmap from mSoftCache
synchronized (mSoftCache) {
if (bitmap != null && !bitmap.isRecycled()) {
mSoftCache.remove(key);

} else {
SoftReference<Bitmap> bitmapReference = mSoftCache.remove(key);
if (bitmapReference != null) {
bitmap = bitmapReference.get();
}
}
}

return bitmap;
}

@Override
public void put(String key, Bitmap bitmap) {
if (bitmap == null || bitmap.isRecycled()) {
return;
}

testLog("put:" + key);
// thread synchronize
synchronized (mMemoryCache) {
mMemoryCache.put(key, bitmap);
}
}

@Override
public void clear() {
synchronized (mMemoryCache) {
mMemoryCache.evictAll();
}

synchronized (mSoftCache) {
mSoftCache.clear();
}
}


private final boolean ISDEBUG = false;

private void testLog(String str) {
if (ISDEBUG) {
MLog.e(TAG, str);
}
}
}


这个缓存是基于LRU算法的缓存机制,LRU即最久未使用算法,当内存不足时将最久未使用的对象放入软引用区,当内存不足时可以及时释放。

[项目的GitHub地址](https://github.com/CJstar/Vinci)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值