概念:
LruCache 什么是LruCache? LruCache实现原理是什么?
这两个问题其实可以作为一个问题来回答,知道了什么是 LruCache,就只然而然的知道 LruCache 的实现原理;Lru的全称是Least Recently Used ,近期最少使用的!所以我们可以推断出 LruCache 的实现原理:把近期最少使用的数据从缓存中移除,保留使用最频繁的数据,那具体代码要怎么实现呢,我们进入到源码中看看。
LruCache源码分析
public class LruCache<K, V> {
private final LinkedHashMap<K, V> map;
private int size;
private int maxSize;
private int putCount;
private int createCount;
private int evictionCount;
private int hitCount;
private int missCount;
public LruCache(
int maxSize) {
if (maxSize <=
0) {
throw new IllegalArgumentException(
"maxSize <= 0");
}
this.maxSize = maxSize;
this.map =
new LinkedHashMap<K, V>(
0,
0.75f,
true);
}
public void resize(
int maxSize) {
if (maxSize <=
0) {
throw new IllegalArgumentException(
"maxSize <= 0");
}
synchronized (
this) {
this.maxSize = maxSize;
}
trimToSize(maxSize);
}
public final V
get(K key) {
if (key ==
null) {
throw new NullPointerException(
"key == null");
}
V mapValue;
synchronized (
this) {
mapValue = map.
get(key);
if (mapValue !=
null) {
hitCount++;
return mapValue;
}
missCount++;
}
V createdValue = create(key);
if (createdValue ==
null) {
return null;
}
synchronized (
this) {
createCount++;
mapValue = map.put(key, createdValue);
if (mapValue !=
null) {
map.put(key, mapValue);
}
else {
size += safeSizeOf(key, createdValue);
}
}
if (mapValue !=
null) {
entryRemoved(
false, key, createdValue, mapValue);
return mapValue;
}
else {
trimToSize(maxSize);
return createdValue;
}
}
public final V
put(K key, V
value) {
if (key ==
null ||
value ==
null) {
throw new NullPointerException(
"key == null || value == null");
}
V previous;
synchronized (
this) {
putCount++;
size += safeSizeOf(key,
value);
previous = map.put(key,
value);
if (previous !=
null) {
size -= safeSizeOf(key, previous);
}
}
if (previous !=
null) {
entryRemoved(
false, key, previous,
value);
}
trimToSize(maxSize);
return previous;
}
private void trimToSize(
int maxSize) {
while (
true) {
K key;
V
value;
synchronized (
this) {
if (size <
0 || (map.isEmpty() && size !=
0)) {
throw new IllegalStateException(getClass().getName()
+
".sizeOf() is reporting inconsistent results!");
}
if (size <= maxSize) {
break;
}
Map.Entry<K, V> toEvict =
null;
for (Map.Entry<K, V> entry : map.entrySet()) {
toEvict = entry;
}
if (toEvict ==
null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key,
value);
evictionCount++;
}
entryRemoved(
true, key,
value,
null);
}
}
public final V
remove(K key) {
if (key ==
null) {
throw new NullPointerException(
"key == null");
}
V previous;
synchronized (
this) {
previous = map.remove(key);
if (previous !=
null) {
size -= safeSizeOf(key, previous);
}
}
if (previous !=
null) {
entryRemoved(
false, key, previous,
null);
}
return previous;
}
protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
protected V
create(K key) {
return null;
}
private int safeSizeOf(K key, V
value) {
int result = sizeOf(key,
value);
if (result <
0) {
throw new IllegalStateException(
"Negative size: " + key +
"=" +
value);
}
return result;
}
protected int sizeOf(K key, V
value) {
return 1;
}
public final
void evictAll() {
trimToSize(-
1);
}
public synchronized final
int size() {
return size;
}
public synchronized final
int maxSize() {
return maxSize;
}
public synchronized final
int hitCount() {
return hitCount;
}
public synchronized final
int missCount() {
return missCount;
}
public synchronized final
int createCount() {
return createCount;
}
public synchronized final
int putCount() {
return putCount;
}
public synchronized final
int evictionCount() {
return evictionCount;
}
public synchronized final Map<K, V>
snapshot() {
return new LinkedHashMap<K, V>(map);
}
}
LruCache 使用
先来看两张内存使用的图
图-1
图-2
以上内存分析图所分析的是同一个应用的数据,唯一不同的是图-1没有使用 LruCache,而图-2使用了 LruCache;可以非常明显的看到,图-1的内存使用明显偏大,基本上都是在30M左右,而图-2的内存使用情况基本上在20M左右。这就足足省了将近10M的内存!
ok,下面把实现代码贴出来
/**
* Created by gyzhong on 15/4/5.
*/
public class LruPageAdapter extends PagerAdapter {
private List<String> mData ;
private LruCache<String,Bitmap> mLruCache ;
private int mTotalSize = (
int) Runtime.getRuntime().totalMemory();
private ViewPager mViewPager ;
public LruPageAdapter(ViewPager viewPager ,List<String> data){
mData = data ;
mViewPager = viewPager ;
mLruCache =
new LruCache<String,Bitmap>(mTotalSize/
5){
@Override
protected void entryRemoved(
boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
super.entryRemoved(evicted, key, oldValue, newValue);
if (evicted && oldValue !=
null){
oldValue.recycle();
}
}
@Override
protected Bitmap
create(String key) {
final int resId = mViewPager.getResources().getIdentifier(key,
"drawable",
mViewPager.getContext().getPackageName()) ;
return BitmapFactory.decodeResource(mViewPager.getResources(),resId) ;
}
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
} ;
}
@Override
public Object
instantiateItem(ViewGroup container,
int position) {
View view = LayoutInflater.from(container.getContext()).inflate(R.layout.view_pager_item,
null) ;
ImageView imageView = (ImageView) view.findViewById(R.id.id_view_pager_item);
Bitmap bitmap = mLruCache.get(mData.get(position));
imageView.setImageBitmap(bitmap);
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container,
int position, Object object) {
container.removeView((View) object);
}
@Override
public int getCount() {
return mData.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
总结
1、LruCache 是基于 Lru算法实现的一种缓存机制; 2、Lru算法的原理是把近期最少使用的数据给移除掉,当然前提是当前数据的量大于设定的最大值。 3、LruCache 没有真正的释放内存,只是从 Map中移除掉数据,真正释放内存还是要用户手动释放。