当前位置: 首页 > 工具软件 > DiskLruCache > 使用案例 >

android强制缓存写磁盘,Android使用磁盘缓存DiskLruCache

龙弘济
2023-12-01

DiskLruCache 不同于LruCache,LruCache是将数据缓存到内存中去,而DiskLruCache是外部缓存,例如可以将网络下载的图片永久的缓存到手机外部存储中去,并可以将缓存数据取出来使用,DiskLruCache不是google官方所写,但是得到了官方推荐,DiskLruCache没有编写到SDK中去,如需使用可直接copy这个类到项目中去。DiskLruCache常用方法:方法备注DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)打开一个缓存目录,如果没有则首先创建它,directory:指定数据缓存地址 appVersion:APP版本号,当版本号改变时,缓存数据会被清除 valueCount:同一个key可以对应多少文件 maxSize:最大可以缓存的数据量

Editor edit(String key)通过key可以获得一个DiskLruCache.Editor,通过Editor可以得到一个输出流,进而缓存到本地存储上

void flush()强制缓冲文件保存到文件系统

Snapshot get(String key)通过key值来获得一个Snapshot,如果Snapshot存在,则移动到LRU队列的头部来,通过Snapshot可以得到一个输入流InputStream

long size()缓存数据的大小,单位是byte

boolean remove(String key)根据key值来删除对应的数据,如果该数据正在被编辑,则不能删除

void delete()关闭缓存并且删除目录下所有的缓存数据,即使有的数据不是由DiskLruCache 缓存到本目录的

void close()关闭DiskLruCache,缓存数据会保留在外存中

boolean isClosed()判断DiskLruCache是否关闭,返回true表示已关闭

File getDirectory()缓存数据的目录如何使用DiskLruCache:

1、因为要操作外部存储,所以必须要先加上权限:

另外要从网络下载图片,还要加上权限:

2、DiskLruCache是在外部存储上(如SD卡),所以首先判断外部存储是否存在:/**

* Get a usable cache directory (external if available, internal otherwise).

* external:如:/storage/emulated/0/Android/data/package_name/cache

* internal 如:/data/data/package_name/cache

*

* @param context    The context to use

* @param uniqueName A unique directory name to append to the cache dir

* @return The cache dir

*/

public static File getDiskCacheDir(Context context, String uniqueName) {      final String cachePath = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||!isExternalStorageRemovable()

? context.getExternalCacheDir().getPath()

: context.getCacheDir().getPath();      return new File(cachePath + File.separator + uniqueName);

}

(1)、首先判断外部缓存是否被移除或已存满,如果已存满或者外存储被移除,则缓存目录=context.getCacheDir().getPath(),即存到 /data/data/package_name/cache 这个文件系统目录下;

(2)、反之缓存目录=context.getExternalCacheDir().getPath(),即存到 /storage/emulated/0/Android/data/package_name/cache 这个外部存储目录中,PS:外部存储可以分为两种:一种如上面这种路径 (/storage/emulated/0/Android/data/package_name/cache), 当应用卸载后,存储数据也会被删除,另外一种是永久存储,即使应用被卸载,存储的数据依然存在,存储路径如:/storage/emulated/0/mDiskCache,可以通过Environment.getExternalStorageDirectory().getAbsolutePath() + "/mDiskCache" 来获得路径。

3、根据URL下载一个在线图片并把它写到输出流outputstream中:/**

* Download a bitmap from a URL and write the content to an output stream.

*

* @param urlString The URL to fetch

* @return true if successful, false otherwise

*/

private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {

HttpURLConnection urlConnection = null;

BufferedOutputStream out = null;

BufferedInputStream in = null;        try {            final URL url = new URL(urlString);

urlConnection = (HttpURLConnection) url.openConnection();

in = new BufferedInputStream(urlConnection.getInputStream(), IO_BUFFER_SIZE);

out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);

int b;            while ((b = in.read()) != -1) {

out.write(b);

}            return true;

} catch (Exception e) {

Log.e(TAG, "Error in downloadBitmap - " + e);

} finally {            if (urlConnection != null) {

urlConnection.disconnect();

}            try {                if (out != null) {

out.close();

}                if (in != null) {

in.close();

}

} catch (final IOException e) {

}

}        return false;

}

4、上面已经下载了图片,接着初始化DiskLruCache,并使用DiskLruCache.Editor准备缓存:private static final int MAX_SIZE = 10 * 1024 * 1024;//10MB

private DiskLruCache diskLruCache;    private void initDiskLruCache() {        if (diskLruCache == null || diskLruCache.isClosed()) {            try {

File cacheDir = CacheUtil.getDiskCacheDir(this, "CacheDir");                if (!cacheDir.exists()) {

cacheDir.mkdirs();

}                //初始化DiskLruCache

diskLruCache = DiskLruCache.open(cacheDir, 1, 1, MAX_SIZE);

} catch (IOException e) {

e.printStackTrace();

}

}

}

下载图片时需要放在异步线程里,这里放在了AsyncTask的doInBackground中:@Overrideprotected Boolean doInBackground(Object... params) {    try {

String key = Util.hashKeyForDisk(Util.IMG_URL);

DiskLruCache diskLruCache = (DiskLruCache) params[0];         //得到DiskLruCache.Editor

DiskLruCache.Editor editor = diskLruCache.edit(key);        if (editor != null) {

OutputStream outputStream = editor.newOutputStream(0);            if (downloadUrlToStream(Util.IMG_URL, outputStream)) {

publishProgress("");                //写入缓存

editor.commit();

} else {                 //写入失败

editor.abort();

}

}

diskLruCache.flush();

} catch (IOException e) {

e.printStackTrace();        return false;

}    return true;

}

上面代码中有个hashKeyForDisk()方法,其作用是把图片URL经过MD5加密生成唯一的key值,避免了URL中可能含有非法字符问题,hashKeyForDisk()代码如下:/**

* A hashing method that changes a string (like a URL) into a hash suitable for using as a

* disk filename.

*/

public static 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 static String bytesToHexString(byte[] bytes) {     // http://stackoverflow.com/questions/332079

StringBuilder sb = new StringBuilder();     for (int i = 0; i 

String hex = Integer.toHexString(0xFF & bytes[i]);         if (hex.length() == 1) {

sb.append('0');

}

sb.append(hex);

}     return sb.toString();

}

经过上面的代码,我们已经可以看到图片已经缓存到 /storage/emulated/0/Android/data/package_name/cache/CacheDir 这个目录下了:

第一个标识为110.78kb大小的就是我们缓存下来的图片,它的名字正是由图片的URL经过MD5加密得到的,它下面的journal文件是用来记录的,来看里面的内容:

第一行:libcore.io.DiskLruCache固定写死

第二行:DiskLruCache版本号

第三行:APP版本号,由open()方法的参数appVersion传入

第四行:同一个key可以对应多少文件,由open()方法的参数valueCount传入,一般为1

第五行:空格

第六行:以DIRTY开头,后面跟着的是图片的key值,表示准备缓存这张图片,当调用DiskLruCache的edit()时就会生成这行记录

第七行: 以CLEAN开头,后面跟着的是图片的Key值和大小,当调用editor.commit()时会生成这条记录,表示缓存成功;如果调用editor.abort()表示缓存失败,则会生成REMOVE开头的表示删除这条数据。

5、通过diskLruCache.get(key)得到DiskLruCache.Snapshot,key是经过MD5加密后那个唯一的key,接着使用Snapshot.getInputStream()可以得到输入流InputStream ,进而得到缓存图片:private Bitmap getCache() {     try {

String key = Util.hashKeyForDisk(Util.IMG_URL);

DiskLruCache.Snapshot snapshot = diskLruCache.get(key);         if (snapshot != null) {

InputStream in = snapshot.getInputStream(0);             return BitmapFactory.decodeStream(in);

}

} catch (IOException e) {

e.printStackTrace();

}     return null;

}Bitmap bitmap = getCache();     if (bitmap != null) {

iv_img.setImageBitmap(bitmap);

}

 类似资料: