【安卓筆記】硬碟快取工具類的編寫
DiskLruCache(https://github.com/JakeWharton/DiskLruCache)想必大家都很熟悉。(不熟悉的請看這裡),它是jakewharton大神寫的一個開源庫,提供了硬碟快取的方案。
但是該庫的API比較簡單,有時候並不能滿足我們使用。比如說如果你想把快取中的資料以Bitmap的形式返回,API並沒有提供這樣的方法,我們必須通過DiskLruCache#get方法返回來的Snapshot獲得輸入流,然後將流轉化為Bitmap。另外,構建DiskLruCache時必須要傳入VersionCode,CachePath等變數,而實際開發中,Versioncode通常是應用版本號,Cachepath也相對固定(要麼是sd的快取目錄要麼是本地的快取目錄),每次構建DiskLruCache都要寫獲取版本號等等重複的程式碼實在是太枯燥了。再比如說,寫快取時需要指定key,而這個key在專案中通常是url,而url中可能有特殊字元,這將導致寫快取失敗,我們最好將url進行編碼,然後使用編碼後的key,而在API中並沒有提供類似的方法。鑑於此,我寫了一個基於DiskLruCache的工具類,進一步簡化快取操作。
這個工具類主中的方法全部是靜態的,可直接呼叫。它的功能有:1.構建快取物件;2.讀快取。將快取讀為String/流/Bitmap;3.寫快取。可以將String/File/流/Bitmap寫入快取,並支援非同步寫入。
說了這麼多,下面來看這個工具類是怎樣寫的吧。
package com.jakewharton.disklrucache;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.text.TextUtils;
/**
* @author Rowandjj
*
*DiskLruCache的輔助工具類(DiskLruCache:http://jakewharton.github.io/DiskLruCache)
* 提供建立/讀取/寫入快取的方法,並支援非同步快取寫入.
*/
public class DiskLruCacheHelper
{
private static final long DEFAULT_MAX_SIZE = 10*1024*1024;
private static ExecutorService service = null;
/**
*
* 建立DiskLruCache例項,預設版本號為當前應用版本號,快取位置由getDiskCacheDir指定
* @param context 上下文
* @param cacheDirName 快取資料夾名稱
* @param maxSize 快取最大值,單位是byte
* @return 建立成功返回DiskLruCache例項否則返回null
*/
public static DiskLruCache createCache(Context context,String cacheDirName,long maxSize)
{
DiskLruCache cache = null;
try
{
cache = DiskLruCache.open(getDiskCacheDir(cacheDirName, context), getAppVersion(context),1, maxSize);
} catch (IOException e)
{
e.printStackTrace();
}
return cache;
}
/**
* 返回一個具有預設大小的DiskLruCache例項,預設大小為10Mb
* @param context
* @param cacheDirName
* @return 建立成功返回DiskLruCache例項否則返回null
*/
public static DiskLruCache createCache(Context context,String cacheDirName)
{
return createCache(context, cacheDirName, DEFAULT_MAX_SIZE);
}
/**
* 將圖片寫入快取
*/
public static boolean writeBitmapToCache(DiskLruCache cache,Bitmap bitmap,String url)
{
return writeBitmapToCache(cache, bitmap, url, CompressFormat.JPEG,100);
}
/**
* 非同步地將圖片寫入快取。將不會不會寫入結果。
* @param cache
* @param bitmap
* @param url
*/
public static void asyncWriteBitmapToCache(final DiskLruCache cache,final Bitmap bitmap,final String url)
{
if(service == null)
service = Executors.newSingleThreadExecutor();
service.execute(new Runnable()
{
@Override
public void run()
{
writeBitmapToCache(cache, bitmap, url);
}
});
}
/**
* 將圖片寫入快取
* @param cache 快取物件
* @param bitmap 圖片物件
* @param url 用於標識bitmap的唯一名稱,通常為圖片url
* @return true表示寫入快取成功否則為false
*/
public static boolean writeBitmapToCache(DiskLruCache cache,Bitmap bitmap,String url,CompressFormat format, int quality)
{
if(cache == null || bitmap == null || url == null || TextUtils.isEmpty(url))
return false;
try
{
DiskLruCache.Editor editor = cache.edit(generateKey(url));
if(editor != null)
{
OutputStream out = editor.newOutputStream(0);
if(bitmap.compress(format,quality, out))
{
editor.commit();
return true;
}
else
{
editor.abort();
}
}
} catch (IOException e)
{
e.printStackTrace();
}
return false;
}
/**
* 非同步地將圖片寫入快取。將不會不會寫入結果。
*/
public static void asyncWriteBitmapToCache(final DiskLruCache cache,final Bitmap bitmap,final String url,final CompressFormat format, final int quality)
{
if(service == null)
service = Executors.newSingleThreadExecutor();
service.execute(new Runnable()
{
@Override
public void run()
{
writeBitmapToCache(cache, bitmap, url,format,quality);
}
});
}
/**
* 非同步地將inputStram流寫入快取,將不會返回寫入結果。
*/
public static void asyncWriteStreamToCache(final DiskLruCache cache,final InputStream in,final String url)
{
if(service == null)
service = Executors.newSingleThreadExecutor();
service.execute(new Runnable()
{
@Override
public void run()
{
asyncWriteStreamToCache(cache, in, url);
}
});
}
/**
* 將inputStram流寫入快取
* @param cache
* @param in
* @param url
* @return
*/
public static boolean writeStreamToCache(DiskLruCache cache,InputStream in,String url)
{
if(cache == null || in == null || url == null|| TextUtils.isEmpty(url))
return false;
DiskLruCache.Editor editor = null;
try
{
editor = cache.edit(generateKey(url));
if(editor != null)
{
OutputStream out = editor.newOutputStream(0);
BufferedInputStream bin = new BufferedInputStream(in);
byte[] buffer = new byte[1024];
int len = 0;
while((len = bin.read(buffer)) != -1)
{
out.write(buffer, 0, len);
out.flush();
}
editor.commit();
return true;
}
} catch (IOException e)
{
e.printStackTrace();
}
return false;
}
/**
* 非同步地將檔案寫入快取,將不會返回寫入結果。
*/
public static void asyncWriteFileToCache(final DiskLruCache cache,final File file,final String url)
{
if(service == null)
service = Executors.newSingleThreadExecutor();
service.execute(new Runnable()
{
@Override
public void run()
{
writeFileToCache(cache, file, url);
}
});
}
/**
* 將檔案寫入快取
* @return true表示寫入成功否則寫入失敗
*/
public static boolean writeFileToCache(DiskLruCache cache,File file,String url)
{
if(cache == null || file == null || url == null || !file.exists() || TextUtils.isEmpty(url))
{
return false;
}
FileInputStream fin = null;
try
{
fin = new FileInputStream(file);
} catch (FileNotFoundException e)
{
e.printStackTrace();
}
return writeStreamToCache(cache, fin, url);
}
/**
* 非同步地將字串寫入快取,將不會返回寫入結果
*/
public static void asyncWriteStringToCache(final DiskLruCache cache,final String str,final String url)
{
if(service == null)
service = Executors.newSingleThreadExecutor();
service.execute(new Runnable()
{
@Override
public void run()
{
writeStringToCache(cache, str, url);
}
});
}
/**
* 將字串寫入快取
* @param cache
* @param str
* @param url
* @return
*/
public static boolean writeStringToCache(DiskLruCache cache,String str,String url)
{
if(cache == null || str == null || url == null || TextUtils.isEmpty(url) || TextUtils.isEmpty(str))
{
return false;
}
DiskLruCache.Editor editor = null;
try
{
editor = cache.edit(generateKey(url));
if(editor != null)
{
OutputStream out = editor.newOutputStream(0);
out.write(str.getBytes());
out.flush();
}
editor.commit();
return true;
} catch (IOException e)
{
e.printStackTrace();
}
return false;
}
/**
* 停止內部正在寫快取的執行緒,
* 這將導致部分寫快取任務不能進行。
*/
public static void stop()
{
if(service != null)
service.shutdownNow();
}
/**
*
* 根據url獲取快取,並將結果以String形式返回
* @param cache
* @param url
* @return 成功則返回String否則返回null
*/
public static String readCacheToString(DiskLruCache cache,String url)
{
if(cache == null || url == null || TextUtils.isEmpty(url))
return null;
String key = generateKey(url);
DiskLruCache.Snapshot snapshot = null;
try
{
snapshot = cache.get(key);
if(snapshot != null)
{
InputStream in = snapshot.getInputStream(0);
StringBuilder builder = new StringBuilder(1024*2);
int len = 0;
byte[] buffer = new byte[1024];
while((len = in.read(buffer)) != -1)
{
builder.append(new String(buffer,0,len));
}
return builder.toString();
}
} catch (Exception e)
{
e.printStackTrace();
}
return null;
}
/**
* 根據url獲取快取,並將快取以InputStream形式返回
*
* @param cache DiskLruCache例項
* @param url 快取名
* @return 命中則返回InputStream流否則返回null
*/
public static InputStream readCacheToInputStream(DiskLruCache cache,String url)
{
if(cache == null || url == null || TextUtils.isEmpty(url))
return null;
String key = generateKey(url);
DiskLruCache.Snapshot snapshot = null;
try
{
snapshot = cache.get(key);
} catch (IOException e)
{
e.printStackTrace();
}
if(snapshot != null)
return snapshot.getInputStream(0);
return null;
}
/**
* 根據url獲取快取,並將快取以Bitmap形式返回
* @param cache
* @param url
* @return 成功返回bitmap,否則返回null
*/
public static Bitmap readCacheToBitmap(DiskLruCache cache,String url)
{
InputStream in = readCacheToInputStream(cache, url);
if(in != null)
return BitmapFactory.decodeStream(in);
return null;
}
/**
* 獲取快取檔案路徑(優先選擇sd卡)
* @param cacheDirName 快取資料夾名稱
* @param context 上下文
* @return
*/
public static File getDiskCacheDir(String cacheDirName,Context context)
{
String cacheDir;
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)&&!Environment.isExternalStorageRemovable())
{
cacheDir = getExternalCacheDir(context);
if(cacheDir == null)//部分機型返回了null
cacheDir = getInternalCacheDir(context);
}else
{
cacheDir = getInternalCacheDir(context);
}
File dir = new File(cacheDir,cacheDirName);
if(!dir.exists())
dir.mkdirs();
return dir;
}
/**
* 獲取當前app版本號
* @param context 上下文
* @return 當前app版本號
*/
public static int getAppVersion(Context context)
{
PackageManager manager = context.getPackageManager();
int code = 1;
try
{
code = manager.getPackageInfo(context.getPackageName(),0).versionCode;
} catch (NameNotFoundException e)
{
e.printStackTrace();
}
return code;
}
/**
* 根據指定的url移除指定快取
* Note:請不要是使用DiskLruCache.remove()
*
* @param cache
* @param url
* @return
*/
public static boolean remove(DiskLruCache cache,String url)
{
if(cache == null || url == null || TextUtils.isEmpty(url))
{
return false;
}
try
{
return cache.remove(generateKey(url));
} catch (IOException e)
{
e.printStackTrace();
}
return false;
}
/**
* 根據原始鍵生成新鍵,以保證鍵的名稱的合法性
* @param key 原始鍵,通常是url
* @return
*/
public static String generateKey(String key)
{
String cacheKey;
try
{
MessageDigest digest = MessageDigest.getInstance("md5");
digest.update(key.getBytes());
cacheKey = bytesToHexString(digest.digest());
} catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
cacheKey = String.valueOf(key.hashCode());
}
return cacheKey;
}
private static String bytesToHexString(byte[] bytes)
{
StringBuilder builder = new StringBuilder();
for(int i = 0; i < bytes.length; i++)
{
String hex = Integer.toHexString(0xff&bytes[i]);
if(hex.length() == 1)
builder.append('0');
builder.append(hex);
}
return builder.toString();
}
private static String getExternalCacheDir(Context context)
{
File dir = context.getExternalCacheDir();
if(dir == null)
return null;
if(!dir.exists())
dir.mkdirs();
return dir.getPath();
}
private static String getInternalCacheDir(Context context)
{
File dir = context.getCacheDir();
if(!dir.exists())
dir.mkdirs();
return dir.getPath();
}
}
程式碼比較簡單,而且都有註釋,我就不過多解釋了。
以後在開發中,如果需要構建DiskLruCache,呼叫DiskLruCacheHelper.createCache,取快取呼叫DiskLruCacheHelper.readCacheToXX,寫快取呼叫DiskLruCacheHelper.writeXXtoCache,非同步寫呼叫DiskLruCacheHelper.asyncWriteXXtoCache,移除指定快取呼叫DiskLruCacheHelper.remove。是不是很方便?
相關文章
- Android 快取工具 DiskLruCache 學習筆記Android快取筆記
- java工具類編寫思考Java
- HTTP快取筆記(1)HTTP快取筆記
- Android 擼一個快取工具類Android快取
- SDWebImage 快取機制(筆記)Web快取筆記
- CrazyDiskInfo硬碟檢測工具 安裝記錄硬碟
- @Cacheable關於快取的個人筆記快取筆記
- windows10系統怎麼開啟硬碟寫入快取Windows硬碟快取
- Rust編寫的Memcached快取替代品:memc.rsRust快取
- 如何用GO語言編寫快取服務?Go快取
- 安卓學習筆記20:Fragment入門安卓筆記Fragment
- 安卓開發筆記——數獨遊戲安卓筆記遊戲
- 安卓初學基礎學習筆記安卓筆記
- 淺談快取寫法(三):記憶體快取該如何設計快取記憶體
- Django筆記三十三之快取操作Django筆記快取
- 《分散式快取》讀書筆記二分散式快取筆記
- 安卓中高階開發面試知識點之——快取安卓面試快取
- 安卓平臺編寫C++演算法SDK流程安卓C++演算法
- FFmpeg開發筆記(十四)FFmpeg音訊重取樣的快取筆記音訊快取
- 安卓Glide(4.7.1)使用筆記 01 - 引入專案安卓IDE筆記
- 淺談快取寫法(一):快取的雪崩和穿透快取穿透
- 簡易筆記:瀏覽器快取策略筆記瀏覽器快取
- 為什麼我拒絕用Kotlin編寫安卓應用?Kotlin安卓
- Redis 的高效能快取機制的三類問題:快取擊穿、快取雪崩 和 快取穿透Redis快取穿透
- 安卓學習筆記---開篇(目錄結構)安卓筆記
- 適合寫筆記的文字筆記管理工具Keep It for Mac好用嗎?筆記Mac
- CPU快取一致性整理筆記快取筆記
- 快取淘汰、快取穿透、快取擊穿、快取雪崩、資料庫快取雙寫一致性快取穿透資料庫
- CDN快取學習筆記,讀騰訊雲的一些心得和整理筆記快取筆記
- 用Java寫一個分散式快取——快取管理Java分散式快取
- .net使用CSRedis操作Redis快取的簡單筆記(新手教程)Redis快取筆記
- 後端工程師入門安卓開發筆記(一)後端工程師安卓筆記
- 程式設計師筆記|如何編寫優雅的Dockerfile程式設計師筆記Docker
- 編寫表DAO類
- [TIL] 使用scrcpy映象安卓裝置+編寫一個Raycast擴充套件安卓AST套件
- 【轉】一個小工具類,利用shareObject把資料快取Object快取
- js類的筆記JS筆記
- 筆記本記憶體和硬碟選購攻略 筆記本如何選擇記憶體和硬碟?筆記記憶體硬碟
- Django筆記二十之手動編寫migration檔案Django筆記