Google又提供了一套硬盘缓存的解决方案:DiskLruCache(非Google官方编写,但获得官方认证)。
那么我们先来看一下有哪些应用程序已经使用了DiskLruCache技术。在我所接触的应用范围里,Dropbox、Twitter、网易新闻等都是使用DiskLruCache来进行硬盘缓存的,其中Dropbox和Twitter大多数人应该都没用过,那么我们就从大家最熟悉的网易新闻开始着手分析,来对DiskLruCache有一个最初的认识吧。
使用:
DiskLruCache没有限制数据的缓存位置,可以自由地进行设定,但是通常情况下多数应用程序都会将缓存的位置选择为 /sdcard/Android/data//cache 这个路径。选择在这个位置有两点好处:第一,这是存储在SD卡上的,因此即使缓存再多的数据也不会对手机的内置存储空间有任何影响,只要SD卡空间足够就行。第二,这个路径被Android系统认定为应用程序的缓存路径,当程序被卸载的时候,这里的数据也会一起被清除掉,这样就不会出现删除程序之后手机上还有很多残留数据的问题。
implementation 'com.jakewharton:disklrucache:2.0.2'
参数:
public DiskCache(File directory, long maxSize) {
try {
if (mDiskLruCache == null || mDiskLruCache.isClosed()) {
mDiskLruCache = DiskLruCache.open(directory, 1, 1, maxSize);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 保存bitmap到磁盘
* 通过图片url 然后md5 加密的内容,作为key 来保存bitmap 对象
*
* @param url 图片请求url --》 md5 去除特殊字符
* @param bitmap
*/
public void saveBitmap(final String url) {
new Thread() {
@Override
public void run() {
super.run();
try {
String key = Utils.hashKeyForDisk(url);
//editor 操作数据保存逻辑
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
OutputStream outputStream = editor.newOutputStream(0);
// 下载图片
if (downloadImage(url, outputStream)) {
editor.commit();
} else {
editor.abort();
}
//别忘了关闭流和提交编辑
outputStream.close();
mDiskLruCache.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
/**
* 通过url 获取md5加密后的key。然后通过key 获取bitmap 对象
*
* @param url
* @return
*/
public Bitmap getBitmap(String url) {
//使用DiskLruCache获取缓存,需要传入key,而key是imageUrl加密后的字符串,
Bitmap bitmap = null;
String key = Utils.hashKeyForDisk(url);
//通过key获取的只是一个快照
DiskLruCache.Snapshot snapshot = null;
try {
snapshot = mDiskLruCache.get(key);
} catch (IOException e) {
e.printStackTrace();
}
if (snapshot != null) {
InputStream inputStream = snapshot.getInputStream(0);//类似写缓存时候,传入的是缓存的编号
//可以使用bitmapFactory
bitmap = BitmapFactory.decodeStream(inputStream);
}
return bitmap;
}
libcore.io.DiskLruCache
1
100
1
DIRTY 335c4c6028171cfddfbaae1a9c313c52
CLEAN 335c4c6028171cfddfbaae1a9c313c52 2342
REMOVE 335c4c6028171cfddfbaae1a9c313c52
DIRTY 1ab96a171faeeee38496d8b330771a7a
CLEAN 1ab96a171faeeee38496d8b330771a7a 1600
READ 335c4c6028171cfddfbaae1a9c313c52
READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
Utils .java
public class Utils {
private static final String TAG = "Utils";
/**
* 获取缓存文件夹,这里优先选择SD卡下面的android/data/packageName/cache/路径,若没有SD卡,就选择data/data/packageName/cache
*
* @param context 上下文环境
* @param uniqueName 缓存文件夹名称
* @return 返回缓存文件
*/
public static File getDiskCacheDir(Context context, String uniqueName) {
String cachePath;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|| !Environment.isExternalStorageRemovable()) {
cachePath = context.getExternalCacheDir().getPath();
} else {
cachePath = context.getCacheDir().getPath();
}
File file = new File(cachePath + File.separator + uniqueName);
Log.d(TAG, "getDiskCacheDir: file="+file.getAbsolutePath());
return file;
}
/**
* 获取本App的版本号
*
* @param context context上下文
* @return 返回版本号
*/
public static int getAppVersion(Context context) {
try {
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return info.versionCode;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return 1;
}
/**
* 给字符串来个md5加密,
* @param key 需要加密的string
* @return 返回加密后的string ,或者加密失败,就返回string的哈希值
*/
public static String hashKeyForDisk(String key) {
String cacheKey;
try {
//md5加密
MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(key.getBytes());
cacheKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
//若md5加密失败,就用哈希值
cacheKey = String.valueOf(key.hashCode());
}
return cacheKey;
}
/**
* 字节数组转为十六进制字符串
* @param bytes 字节数组
* @return 返回十六进制字符串
*/
private static String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xFF & b);
if (hex.length()==1){
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
}
DiskCache.java
public class DiskCache {
private static final String TAG = "DiskCache";
DiskLruCache mDiskLruCache;
// 初始化
public DiskCache(File directory, long maxSize) {
try {
if (mDiskLruCache == null || mDiskLruCache.isClosed()) {
mDiskLruCache = DiskLruCache.open(directory, 1, 1, maxSize);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 保存bitmap到磁盘
* 通过图片url 然后md5 加密的内容,作为key 来保存bitmap 对象
*
* @param url 图片请求url --》 md5 去除特殊字符
* @param bitmap
*/
public void saveBitmap(final String url, Bitmap bitmap) {
new Thread() {
@Override
public void run() {
super.run();
try {
String key = Utils.hashKeyForDisk(url);
//editor 操作数据保存逻辑
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
OutputStream outputStream = editor.newOutputStream(0);
// 下载图片
if (downloadImage(url, outputStream)) {
editor.commit();
} else {
editor.abort();
}
//别忘了关闭流和提交编辑
outputStream.close();
mDiskLruCache.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
/**
* 通过url 获取md5加密后的key。然后通过key 获取bitmap 对象
*
* @param url
* @return
*/
public Bitmap getBitmap(String url) {
//使用DiskLruCache获取缓存,需要传入key,而key是imageUrl加密后的字符串,
Bitmap bitmap = null;
String key = Utils.hashKeyForDisk(url);
//通过key获取的只是一个快照
DiskLruCache.Snapshot snapshot = null;
try {
snapshot = mDiskLruCache.get(key);
} catch (IOException e) {
e.printStackTrace();
}
if (snapshot != null) {
InputStream inputStream = snapshot.getInputStream(0);//类似写缓存时候,传入的是缓存的编号
//可以使用bitmapFactory
bitmap = BitmapFactory.decodeStream(inputStream);
}
return bitmap;
}
/**
* 下载图片
*
* @param imgUrl 图片网址链接
* @param outputStream 输出流对象
* @return 返回时候完成下载成功
*/
private boolean downloadImage(String imgUrl, OutputStream outputStream) {
HttpURLConnection urlConnection = null;
BufferedOutputStream out = null;
BufferedInputStream in = null;
try {
URL url = new URL(imgUrl);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream(), 2 * 1024);//Buffer输入流,8M大小的缓存
out = new BufferedOutputStream(outputStream, 2 * 1024);
int b;//正在读取的byte
while ((b = in.read()) != -1) {
out.write(b);
}
return true;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//关闭资源
finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}
}