关于LruCache内存缓存管理类
android.util.LruCache<K, V>是一个Android官方提供的内存缓存管理类,它是在Android 3.1(代号 Honeycomb MR1)引入的。LruCache可以在创建时定义缓存的最大长度,而且还可以通过覆写sizeof()方法改变每个缓存条目计算大小的方式。由于android.util.LruCache是在Android 3.1版本才引入的API,所以只能在Android 3.1及更高版本上使用。但是为了兼容Android 3.1以下版本的设备,我们需要在工程中引用android-support-v4.jar库(新版本的Eclipse在新建工程的时候就自动引用了)。
我们可以通过LruCache类来进行图片的内存缓存管理。
关于DiskLruCache磁盘缓存管理类
Google提供了一套硬盘缓存的解决方案:DiskLruCache(非Google官方编写,但获得官方认证)。像官方的LruCache一样,DiskLruCache不但提供了缓存文件的写入、读取、删除基本功能,还提供了定义缓存大小的方法,同时还具备了缓存文件绑定版本号以及设定一个key对应的文件数等功能。
我们可以通过DiskLruCache类来进行图片的磁盘缓存管理。使用之前需要在工程中引用DiskLruCache的jar包。
点击这里下载DiskLruCache.jar。
一、内存磁盘两级缓存的架构设计如下:
二、工作流程如下:
1、先调用内存缓存管理获取内存缓存中图片显示,结果为空则进行下一步;
2、调用磁盘缓存管理类获取磁盘缓存中图片显示,如果有则显示,并将其保存到内存缓存中,如果为空则进行下一步;
3、从网络中请求图片,将请求结果显示,并保存到内存缓存和磁盘缓存中。
三、实现内存缓存管理类
实现一个名为ImageLruCache类,用来管理图片的内存缓存:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import android.content.Context;
import android.os.Build;
import android.support.v4.util.LruCache;
import android.util.Log;
import android.graphics.Bitmap;
public class ImageLruCache{
public static final String TAG = ImageLruCache.class.getSimpleName();
private LruCache<String, Bitmap> mMemoryCache;
private ImageDiskLruCache mImageDiskLruCache;
//构造函数
public ImageLruCache(Context context){
// 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。
// LruCache通过构造函数传入缓存值,以KB为单位。
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// 使用最大可用内存值的1/8作为缓存的大小。
int cacheSize = maxMemory / 8;
Log.i(TAG, "The Size of MemoryCache is " + cacheSize/1024 + " MB");
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// 重写此方法来衡量每张图片的大小,默认返回图片数量。
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1 ){
return bitmap.getByteCount() / 1024;
}else{
return bitmap.getRowBytes()*bitmap.getHeight() / 1024;
}
}
};
mImageDiskLruCache = new ImageDiskLruCache(context);
}
//添加图片进缓存
@Override
public void putBitmap(final String url, final Bitmap bitmap) {
final String key = hashKeyForLruCache(url);
mMemoryCache.put(key, bitmap);
new Thread(new Runnable() {
@Override
public void run() {
mImageDiskLruCache.addBitmapToDiskCache(url, bitmap);
}
}).start();
return;
}
//从缓存中取出图片
@Override
public Bitmap getBitmap(String url) {
String key = hashKeyForLruCache(url);
Bitmap bm = mMemoryCache.get(key);
if(bm != null){
return bm;
}
else
{
bm = mImageDiskLruCache.getBitmapFromDiskCache(url);
if (bm != null) {
mMemoryCache.put(key, bm);
}
return bm;
}
}
//删除缓存文件
public boolean removeBitmap(String url) {
String key = hashKeyForLruCache(url);
mMemoryCache.remove(key);
return mImageDiskLruCache.removeImageFromDiskCache(url);
}
//将key进行MD5编码
public String hashKeyForLruCache(String key) {
String cacheKey;
try {
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(key.getBytes());
cacheKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) {
cacheKey = String.valueOf(key.hashCode());
}
return cacheKey;
}
private String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
}
1、类中将内存缓存的大小设置为App最大可用内存的1/8;
2、提供putBitmap、getBitmap、removeBitmap三个方法;
3、将图片的键值进行MD5转换后保存。
四、实现磁盘缓存缓存管理类
实现一个名为ImageDiskLruCache类,用来管理图片的磁盘缓存:
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import com.jakewharton.disklrucache.DiskLruCache;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
public class ImageDiskLruCache {
public static final String TAG = ImageDiskLruCache.class.getSimpleName();
private DiskLruCache mDiskLruCache;
private int mDiskCacheSize = 1024 * 1024 * 100; // 100MB
//初始化函数
ImageDiskLruCache(Context context){
try {
File cacheDir = context.getCacheDir();
File imageCacheDir = new File(cacheDir + "/image");
//如果文件夹不存在则创建
if (!imageCacheDir.exists()) {
imageCacheDir.mkdirs();
}
//第一个参数指定的是数据的缓存地址,第二个参数指定当前应用程序的版本号,
//第三个参数指定同一个key可以对应多少个缓存文件,基本都是传1,第四个参数指定最多可以缓存多少字节的数据
mDiskLruCache = DiskLruCache.open(imageCacheDir, getAppVersion(context), 1, mDiskCacheSize);
}
catch (IOException e) {
Log.i(TAG, "fail to open cache");
}
}
//获取应用的版本号
public int getAppVersion(Context context) {
try {
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return info.versionCode;
}
catch (NameNotFoundException e){
e.printStackTrace();
}
return 1;
}
//添加图片到缓存
public void addBitmapToDiskCache(final String data, final Bitmap bitmap) {
if (data == null || bitmap == null) {
return;
}
if (mDiskLruCache != null) {
final String key = hashKeyForDisk(data);
OutputStream out = null;
try {
final DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
if (snapshot == null) {
final DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if (editor != null) {
out = editor.newOutputStream(0);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
editor.commit();
out.close();
mDiskLruCache.flush();
}
} else {
snapshot.getInputStream(0).close();
}
} catch (final IOException e) {
} finally {
try {
if (out != null) {
out.close();
out = null;
}
} catch (final IOException e) {
} catch (final IllegalStateException e) {
}
}
}
}
//从缓存中取出图片
public final Bitmap getBitmapFromDiskCache(final String data) {
if (data == null) {
return null;
}
final String key = hashKeyForDisk(data);//md5生成key
if (mDiskLruCache != null) {
InputStream inputStream = null;
try {
final DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
if (snapshot != null) {
inputStream = snapshot.getInputStream(0);
if (inputStream != null) {
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
if (bitmap != null) {
return bitmap;
}
}
}
} catch (final IOException e) {
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (final IOException e) {
}
}
}
return null;
}
//删除缓存文件
public boolean removeImageFromDiskCache(final String data) {
if (data == null) {
return false;
}
final String key = hashKeyForDisk(data);//md5生成key
if (mDiskLruCache != null) {
try {
boolean remove = mDiskLruCache.remove(key);
return remove;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
return false;
}
//将key进行MD5编码
public String hashKeyForDisk(String key) {
String cacheKey;
try {
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(key.getBytes());
cacheKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) {
cacheKey = String.valueOf(key.hashCode());
}
return cacheKey;
}
private String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
}
1、引用了第三方库DiskLruCache,需要下载DiskLruCache.jar并引入到功能中, 点此下载 。
2、这里将磁盘缓存的大小设置为100M;
3、提供addBitmapToDiskCache、getBitmapFromDiskCache、removeBitmapFromDiskCache三个方法;
4、将图片的键值进行MD5转换后保存。
五、二级缓存的使用
直接调用ImageLruCache的方法就可以实现了二级缓存的存取删除功能。
参考:
http://www.bdqn.cn/news/201307/10432.shtml
http://blog.csdn.net/guolin_blog/article/details/28863651