将LruCache+DiskLruCache+软引用三种缓存技术结合起来,加强图片的缓存效果。
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Environment;
import android.support.v4.util.LruCache;
import com.jakewharton.disklrucache.DiskLruCache;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.SoftReference;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;
public class ImageCache {
private static final String IMAGE_PATH = "image";
private static final int DEFAULT_MEM_CACHE_SIZE = 1024 * 1024 * 8;
private static final int DEFAULT_DIS_CACHE_SIZE = 1024 * 1024 * 10;
private static final int DEDAULT_SOFT_CACHE_NUM = 20;
private LruCache<String, Bitmap> mLruCache;
private DiskLruCache mDisLruCache;
private LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache;
private volatile static ImageCache mImageCache;
private ImageCache(Context context) {
mLruCache = new LruCache<String,Bitmap>(DEFAULT_MEM_CACHE_SIZE) {
@Override
protected int sizeOf(String key, Bitmap value) {
return getBitmapSize(value);
}
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
if (evicted) {
mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));
}
super.entryRemoved(evicted, key, oldValue, newValue);
}
};
try {
mDisLruCache.open(getDiskCacheDir(context), getAppVersion(context), 1, DEFAULT_DIS_CACHE_SIZE);
} catch (IOException e) {
e.printStackTrace();
}
mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(
DEDAULT_SOFT_CACHE_NUM, 0.75f, true) {
private static final long serialVersionUID = 1L;
/**
* 当软引用数量大于20的时候,最旧的软引用将会被从链式哈希表中移出
*/
@Override
protected boolean removeEldestEntry(
Entry<String, SoftReference<Bitmap>> eldest) {
if (size() > DEDAULT_SOFT_CACHE_NUM) {
return true;
}
return false;
}
};
}
public static ImageCache getInstance(Context context) {
if (mImageCache == null) {
synchronized (ImageCache.class) {
if (mImageCache == null) {
mImageCache = new ImageCache(context);
}
}
}
return mImageCache;
}
/*
* 查看缓存是否存在key的图片,
* 在从网络获取图片之前可以先进行查看,如果没有就网络请求
*
* 策略:先查看mLruCache是否存在该实例对象,即查看内存是否存在该对象
* 再查看mSoftCache是否存在,即查看mLruCache中被回收的对象中是否存在该对象
* 最后查看Disk中是否缓存了该对象
*
* */
public Bitmap get(String key) {
key = hashKey(key);
DiskLruCache.Snapshot snapshot = null;
Bitmap bitmap = mLruCache.get(key);
if (bitmap == null) {
bitmap = mSoftCache.get(key).get();
if (bitmap == null) {
if (mDisLruCache != null) {
try {
snapshot = mDisLruCache.get(key);
if (snapshot != null) {
InputStream is = snapshot.getInputStream(0);
bitmap = BitmapFactory.decodeStream(is);
}
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
mSoftCache.remove(key);
}
if (bitmap != null) {
mLruCache.put(key, bitmap);
}
}
return bitmap;
}
/*
* 从网络获取到图片资源之后,就调用该方法将它进行缓存,
* */
public void put(String key, Bitmap bitmap) {
key = hashKey(key);
mLruCache.put(key, bitmap);
if (mDisLruCache != null) {
try {
DiskLruCache.Editor editor = mDisLruCache.edit(key);
if (editor != null) {
OutputStream outputStream = editor.newOutputStream(0);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
outputStream.write(byteArrayOutputStream.toByteArray());
editor.commit();
mDisLruCache.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* 获取图片大小
* */
private int getBitmapSize(Bitmap bitmap) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
return bitmap.getByteCount();
}
return bitmap.getRowBytes() * bitmap.getHeight();
}
/*
* 得到Disk缓存目标
* */
private File getDiskCacheDir(Context context) {
String cachePath;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
cachePath = context.getExternalCacheDir().getPath();
} else {
cachePath = context.getCacheDir().getPath();
}
return new File(cachePath + File.separator + IMAGE_PATH);
}
/*
* 获取应用版本号
* */
private int getAppVersion(Context context) {
try {
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(),0);
return info.versionCode;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return 1;
}
/*
* 将key编码为MD5
* */
private String hashKey(String key) {
String cacheKey;
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance("MD5");
digest.update(key.getBytes());
cacheKey = bytesToHexString(digest.digest());
} catch (NoSuchAlgorithmException e) {
cacheKey = String.valueOf(key.hashCode());
e.printStackTrace();
}
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();
}
}
参考文章:
Android图片缓存技术