android缓存系列:动手封装DiskLruCache
来源:互联网 发布:app数据查询 编辑:程序博客网 时间:2024/06/05 08:19
这里主要参考了universal imageloader的源码,尝试对DiskLruCache做了一定的封装,代码如下:
DLCHelper
public class DLCHelper { private DiskLruCache cache; protected int bufferSize = DEFAULT_BUFFER_SIZE; public static final int DEFAULT_BUFFER_SIZE = 32 * 1024; // 32 Kb public static final int DEFAULT_CACHE_SIZE = 50 * 1024 * 1024; public static final int DEFALUT_CACHE_FILE_COUNT = Integer.MAX_VALUE; private volatile static DLCHelper instance = null; public static DLCHelper getInstance(Context context) { if (instance == null) { synchronized (DLCHelper.class) { if (instance == null) { instance = new DLCHelper(context); } } } return instance; } // 构造函数 private DLCHelper(Context context) { File individualCacheDir = StorageUtils.getIndividualCacheDirectory(context); try { initCache(individualCacheDir, DEFAULT_CACHE_SIZE, DEFALUT_CACHE_FILE_COUNT); } catch (IOException e) { e.printStackTrace(); } } private void initCache(File cacheDir, long cacheMaxSize, int cacheMaxFileCount) throws IOException { try { cache = DiskLruCache.open(cacheDir, 1, 1, cacheMaxSize, cacheMaxFileCount); } catch (IOException e) { e.printStackTrace(); } } // 获取存储目录 public File getDirectory() { return cache.getDirectory(); } // 移除的方案 public boolean remove(String imageUri) { try { return cache.remove(Md5FileNameGenerator.generate(imageUri)); } catch (IOException e) { e.printStackTrace(); return false; } } // 清空缓存的方法 public void clear() { try { cache.delete(); } catch (IOException e) { e.printStackTrace(); } } // 关闭的方法 public void close() { try { cache.close(); } catch (IOException e) { e.printStackTrace(); } cache = null; } // 取图片缓存的方法 public File get(String imageUri) { DiskLruCache.Snapshot snapshot = null; try { snapshot = cache.get(Md5FileNameGenerator.generate(imageUri)); return snapshot == null ? null : snapshot.getFile(0); } catch (IOException e) { e.printStackTrace(); return null; } finally { if (snapshot != null) { snapshot.close(); } } } // 保存缓存的方法 public boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException { DiskLruCache.Editor editor = cache.edit(Md5FileNameGenerator.generate(imageUri)); if (editor == null) { return false; } OutputStream os = new BufferedOutputStream(editor.newOutputStream(0), bufferSize); boolean copied = false; try { copied = IoUtils.copyStream(imageStream, os, listener, bufferSize); } finally { IoUtils.closeSilently(os); if (copied) { editor.commit(); } else { editor.abort(); } } return copied; } public boolean save(String imageUri, Bitmap bitmap) throws IOException { DiskLruCache.Editor editor = cache.edit(Md5FileNameGenerator.generate(imageUri)); if (editor == null) { return false; } OutputStream os = new BufferedOutputStream(editor.newOutputStream(0), bufferSize); boolean savedSuccessfully = false; try { savedSuccessfully = bitmap.compress(Bitmap.CompressFormat.PNG, 100, os); } finally { IoUtils.closeSilently(os); } if (savedSuccessfully) { editor.commit(); } else { editor.abort(); } cache.flush(); return savedSuccessfully; }}
IoUtils
public final class IoUtils { /** {@value} */ public static final int DEFAULT_BUFFER_SIZE = 32 * 1024; // 32 KB /** {@value} */ public static final int DEFAULT_IMAGE_TOTAL_SIZE = 500 * 1024; // 500 Kb /** {@value} */ public static final int CONTINUE_LOADING_PERCENTAGE = 75; private IoUtils() { } /** * Copies stream, fires progress events by listener, can be interrupted by listener. Uses buffer size = * {@value #DEFAULT_BUFFER_SIZE} bytes. * * @param is Input stream * @param os Output stream * @param listener null-ok; Listener of copying progress and controller of copying interrupting * @return <b>true</b> - if stream copied successfully; <b>false</b> - if copying was interrupted by listener * @throws IOException */ public static boolean copyStream(InputStream is, OutputStream os, CopyListener listener) throws IOException { return copyStream(is, os, listener, DEFAULT_BUFFER_SIZE); } /** * Copies stream, fires progress events by listener, can be interrupted by listener. * * @param is Input stream * @param os Output stream * @param listener null-ok; Listener of copying progress and controller of copying interrupting * @param bufferSize Buffer size for copying, also represents a step for firing progress listener callback, i.e. * progress event will be fired after every copied <b>bufferSize</b> bytes * @return <b>true</b> - if stream copied successfully; <b>false</b> - if copying was interrupted by listener * @throws IOException */ public static boolean copyStream(InputStream is, OutputStream os, CopyListener listener, int bufferSize) throws IOException { int current = 0; int total = is.available(); if (total <= 0) { total = DEFAULT_IMAGE_TOTAL_SIZE; } final byte[] bytes = new byte[bufferSize]; int count; if (shouldStopLoading(listener, current, total)) return false; while ((count = is.read(bytes, 0, bufferSize)) != -1) { os.write(bytes, 0, count); current += count; if (shouldStopLoading(listener, current, total)) return false; } os.flush(); return true; } private static boolean shouldStopLoading(CopyListener listener, int current, int total) { if (listener != null) { boolean shouldContinue = listener.onBytesCopied(current, total); if (!shouldContinue) { if (100 * current / total < CONTINUE_LOADING_PERCENTAGE) { return true; // if loaded more than 75% then continue loading anyway } } } return false; } /** * Reads all data from stream and close it silently * * @param is Input stream */ public static void readAndCloseStream(InputStream is) { final byte[] bytes = new byte[DEFAULT_BUFFER_SIZE]; try { while (is.read(bytes, 0, DEFAULT_BUFFER_SIZE) != -1) { } } catch (IOException e) { // Do nothing } finally { closeSilently(is); } } public static void closeSilently(Closeable closeable) { try { closeable.close(); } catch (Exception e) { // Do nothing } } /** Listener and controller for copy process */ public static interface CopyListener { /** * @param current Loaded bytes * @param total Total bytes for loading * @return <b>true</b> - if copying should be continued; <b>false</b> - if copying should be interrupted */ boolean onBytesCopied(int current, int total); }}
StorageUtils
public final class StorageUtils { private static final String EXTERNAL_STORAGE_PERMISSION = "android.permission.WRITE_EXTERNAL_STORAGE"; private static final String INDIVIDUAL_DIR_NAME = "uil-images"; private StorageUtils() { } /** * Returns application cache directory. Cache directory will be created on SD card * <i>("/Android/data/[app_package_name]/cache")</i> if card is mounted and app has appropriate permission. Else - * Android defines cache directory on device's file system. * * @param context Application context * @return Cache {@link File directory}.<br /> * <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and * {@link android.content.Context#getCacheDir() Context.getCacheDir()} returns null). */ public static File getCacheDirectory(Context context) { return getCacheDirectory(context, true); } /** * Returns application cache directory. Cache directory will be created on SD card * <i>("/Android/data/[app_package_name]/cache")</i> (if card is mounted and app has appropriate permission) or * on device's file system depending incoming parameters. * * @param context Application context * @param preferExternal Whether prefer external location for cache * @return Cache {@link File directory}.<br /> * <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and * {@link android.content.Context#getCacheDir() Context.getCacheDir()} returns null). */ public static File getCacheDirectory(Context context, boolean preferExternal) { File appCacheDir = null; String externalStorageState; try { externalStorageState = Environment.getExternalStorageState(); } catch (NullPointerException e) { // (sh)it happens (Issue #660) externalStorageState = ""; } if (preferExternal && MEDIA_MOUNTED.equals(externalStorageState) && hasExternalStoragePermission(context)) { appCacheDir = getExternalCacheDir(context); } if (appCacheDir == null) { appCacheDir = context.getCacheDir(); } if (appCacheDir == null) { String cacheDirPath = "/data/data/" + context.getPackageName() + "/cache/";// Log.d("Can't define system cache directory! '%s' will be used.", cacheDirPath); appCacheDir = new File(cacheDirPath); } return appCacheDir; } /** * Returns individual application cache directory (for only image caching from ImageLoader). Cache directory will be * created on SD card <i>("/Android/data/[app_package_name]/cache/uil-images")</i> if card is mounted and app has * appropriate permission. Else - Android defines cache directory on device's file system. * * @param context Application context * @return Cache {@link File directory} */ public static File getIndividualCacheDirectory(Context context) { File cacheDir = getCacheDirectory(context); File individualCacheDir = new File(cacheDir, INDIVIDUAL_DIR_NAME); if (!individualCacheDir.exists()) { if (!individualCacheDir.mkdir()) { individualCacheDir = cacheDir; } } return individualCacheDir; } /** * Returns specified application cache directory. Cache directory will be created on SD card by defined path if card * is mounted and app has appropriate permission. Else - Android defines cache directory on device's file system. * * @param context Application context * @param cacheDir Cache directory path (e.g.: "AppCacheDir", "AppDir/cache/images") * @return Cache {@link File directory} */ public static File getOwnCacheDirectory(Context context, String cacheDir) { File appCacheDir = null; if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context)) { appCacheDir = new File(Environment.getExternalStorageDirectory(), cacheDir); } if (appCacheDir == null || (!appCacheDir.exists() && !appCacheDir.mkdirs())) { appCacheDir = context.getCacheDir(); } return appCacheDir; } private static File getExternalCacheDir(Context context) { File dataDir = new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data"); File appCacheDir = new File(new File(dataDir, context.getPackageName()), "cache"); if (!appCacheDir.exists()) { if (!appCacheDir.mkdirs()) {// L.w("Unable to create external cache directory"); return null; } try { new File(appCacheDir, ".nomedia").createNewFile(); } catch (IOException e) {// L.i("Can't create \".nomedia\" file in application external cache directory"); } } return appCacheDir; } private static boolean hasExternalStoragePermission(Context context) { int perm = context.checkCallingOrSelfPermission(EXTERNAL_STORAGE_PERMISSION); return perm == PackageManager.PERMISSION_GRANTED; }}
Md5FileNameGenerator
public class Md5FileNameGenerator { private static final String HASH_ALGORITHM = "MD5"; private static final int RADIX = 10 + 26; // 10 digits + 26 letters public static String generate(String imageUri) { byte[] md5 = getMD5(imageUri.getBytes()); BigInteger bi = new BigInteger(md5).abs(); return bi.toString(RADIX); } private static byte[] getMD5(byte[] data) { byte[] hash = null; try { MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM); digest.update(data); hash = digest.digest(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return hash; }}
我这里的封装主要考虑的是图片。
洪洋之前也封装过一个,具体可见:
https://github.com/hongyangAndroid/base-diskcache
0 0
- android缓存系列:动手封装DiskLruCache
- Android DiskLruCache缓存工具封装
- android缓存系列:DiskLruCache源码分析
- Android DiskLruCache磁盘缓存
- android 文件缓存 DiskLruCache
- Android DiskLruCache硬盘缓存
- Android缓存框架 DiskLruCache
- Android 磁盘缓存 DiskLruCache
- Android DiskLruCache(磁盘缓存)
- Android DiskLruCache(磁盘缓存)
- Android DiskLruCache(磁盘缓存)
- Android缓存之磁盘缓存.对DiskLruCache进行封装便于存取.
- Android DiskLruCache缓存完全解析
- Android DiskLruCache缓存完全解析
- Android DiskLruCache缓存完全解析
- Android DiskLruCache缓存完全解析
- Android 缓存工具DiskLruCache用法
- Android DiskLruCache缓存完全解析
- linux学习-编译内核
- Android中的Adapter 详解(二)
- https://passport.csdn.net/account/fpwd?action=resetpassword&username=s502346787&active=20fcc4dbac25
- android缓存系列:DiskLruCache源码分析
- 搭建Java开发环境
- android缓存系列:动手封装DiskLruCache
- SnackBar(支持上下显示,兼容低版本)
- Android Rxjava之just方法的使用
- 多线程中的基本概念
- 模拟 优先队列(hdu 5437)
- 146. LRU Cache[hard]
- 普通素数筛法
- 3.3 垃圾收集算法
- codeforces 682D(DP)