DiskLruCache并不是Android系統(tǒng)內(nèi)置的緩存類,但是它得到了google的官方推薦,要使用DiskLruCache,首先需要添加依賴:
compile 'com.jakewharton:disklrucache:2.0.2'
創(chuàng)建DiskLruCache
DiskLruCache提供了一個(gè)open方法,用于磁盤緩存的創(chuàng)建。
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
directory表示緩存路徑,appVersion指應(yīng)用版本,valueCount指單個(gè)節(jié)點(diǎn)對(duì)應(yīng)的數(shù)據(jù)大小,設(shè)置為1就好。maxSize指緩存空間大小。
DiskLruCache會(huì)根據(jù)appVersion來識(shí)別當(dāng)前應(yīng)用的版本,如果有更新,會(huì)清除原來的數(shù)據(jù)并重建緩存,可以設(shè)置一個(gè)固定值比如1,這樣在應(yīng)用版本升級(jí)以后并不會(huì)清除原來的緩存。
appVersion應(yīng)用版本號(hào)也可以通過PackageManager來獲取,這樣能保證DiskLruCache對(duì)應(yīng)的總是新的版本:
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return info.versionCode;
這里的獲取的versionCode,是在Manifest文件中定義的:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xxx.xxx.xxxx"
android:versionCode="1">
添加緩存數(shù)據(jù)
DiskLruCache的寫入通過Editor來完成。獲取方法如下:
DiskLruCache.Editor editor = mDiskLruCache.edit(key)
如果key對(duì)應(yīng)的緩存正在被操作(比如正在寫入),會(huì)返回null。而這里的key就是緩存中數(shù)據(jù)存儲(chǔ)的鍵值(比如url),它不允許特殊字符存在,通常我們要對(duì)它進(jìn)行轉(zhuǎn)碼:
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();
}
獲取到對(duì)應(yīng)的editor之后,就可以向緩存寫入數(shù)據(jù)了,寫入數(shù)據(jù)使用的是輸出流的方式,取得當(dāng)前editor的outpStream,就可以寫入數(shù)據(jù)了。
OutputStream outputStream = editor.newOutputStream(0);//獲取輸出流,參數(shù)0表示當(dāng)前key對(duì)應(yīng)的數(shù)據(jù)id,創(chuàng)建DiskLruCache時(shí)傳入的第三個(gè)參數(shù)為1,所以傳入0表示第一個(gè)
完整示例如下:
public boolean putDateToCache(DiskLruCache.Editor editor, InputStream inputStream) {
BufferedInputStream in = null;
BufferedOutputStream out = null;
int b;
try {
OutputStream outputStream = editor.newOutputStream(0);
in = new BufferedInputStream(inputStream, 4*1024);
out = new BufferedOutputStream(outputStream, 4*1024);
while ((b = in.read())!= -1){
out.write(b);
}
editor.commit();
return true;
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (out != null){
out.close();
}
if (in != null){
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
緩存內(nèi)容讀取
讀取緩存內(nèi)容使用的是get方法,它返回一個(gè)Snapshot 對(duì)象,調(diào)用snapshot的getInputStream方法就可以讀取到輸入流了。
try {
DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
if (snapShot != null) {
InputStream is = snapShot.getInputStream(0);
Bitmap bitmap = BitmapFactory.decodeStream(is);
mImage.setImageBitmap(bitmap);
}
} catch (IOException e) {
e.printStackTrace();
}
移除緩存
通常情況下,DiskLruCache會(huì)根據(jù)設(shè)置的緩存大小自動(dòng)管理數(shù)據(jù),但是如果key對(duì)應(yīng)的數(shù)據(jù)過期,可以通過remove方法手動(dòng)移除數(shù)據(jù)。
try {
String key = hashKeyForDisk(imageUrl);
mDiskLruCache.remove(key);
} catch (IOException e) {
e.printStackTrace();
}
其他API:
- size
DiskLruCache的size方法返回緩存路徑下所有數(shù)據(jù)的總量,單位是byte, - flush
flush用于將內(nèi)存中的操作記錄同步到日志文件(也就是journal文件)當(dāng)中。DiskLruCache能夠正常工作的前提就是要依賴于journal文件中的內(nèi)容。并不是每次寫入緩存都要調(diào)用一次flush()方法的,頻繁地調(diào)用會(huì)額外增加同步j(luò)ournal文件的時(shí)間??梢詫⒃趯懭牍ぷ魍瓿梢院笠淮涡詅lush。 - close()
這個(gè)方法用于將DiskLruCache關(guān)閉掉,是和open()方法對(duì)應(yīng)的一個(gè)方法。關(guān)閉掉了之后就不能再調(diào)用DiskLruCache中任何操作緩存數(shù)據(jù)的方法,通常只應(yīng)該在Activity的onDestroy()方法中去調(diào)用close()方法。 - delete()
這個(gè)方法用于將所有的緩存數(shù)據(jù)全部刪除,比如說網(wǎng)易新聞中的那個(gè)手動(dòng)清理緩存功能,其實(shí)只需要調(diào)用一下DiskLruCache的delete()方法就可以實(shí)現(xiàn)了。