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
原创粉丝点击