android 缓存库封装,自己封装双缓存管理框架 Android 库

本文详细介绍了在Android开发中如何实现内存和磁盘级别的缓存管理,使用LruCache进行内存缓存,并借助DiskLruCache实现持久化磁盘缓存。通过自定义MemoryCache和DiskCache类,构建了一个名为XCCacheManager的双缓存管理框架,支持不同的缓存策略,以提高程序性能并优化用户体验。
摘要由CSDN通过智能技术生成

一、概述

Android开发中,网络请求是很重要的一部分,而缓存网络请求来的图片或者响应结果字符串或者结果流,既可以省流量,同时也可以帮助我们解决无网或弱网情况下加载情况,当然也可以提升程序性能效率。纵所周知,缓存管理中肯定需要用到内存缓存,这里我们采用LruCache来管理内存的缓存。

LruCahce虽然速度快,但是只是内存级别的缓存,为了实现持久化的缓存,我们还需要文件级别的缓存,也就是说我们要把缓存保存到文件,而文件则是保存到手机存储或者SD卡存储中,即实现Disk级别的缓存,这里我们借助DiskLruCache这个辅助工具类来实现。顾名思义,这个工具类的作用就是使用Lru算法来存储信息到Disk上。

二、实例效果图

下面是个简单的实例演示效果图

7b5c60f3b612ee98e1d2d63486e9aecb.png

三、缓存管理框架的实现解

1、内存缓存类的实现

该类主要实现内存级别的缓存管理类MemoryCache,使用LruCache来实现,因为无论是内存缓存还是Disk缓存,都需要读写操作,所以我们先抽象出一个缓存接口类:Cache接口:public interface Cache {    String get(final String key);    void put(final String key, final String value);    boolean remove(final String key);

}

然后,我们的内存缓存类MemoryCache需要实现Cache这个接口:/**

* 内存缓存类

* Created by caizhiming on 2015/12/4.

*/public class MemoryCache implements Cache {    private LruCache mMemoryLruCache;    private EvictedListener mEvictedListener;    public MemoryCache() {

init();

}    public MemoryCache(EvictedListener listener) {

init();        this.mEvictedListener = listener;

}    public void setEvictedListener(EvictedListener listener) {        this.mEvictedListener = listener;

}    public boolean hasEvictedListener() {        return mEvictedListener != null;

}    private void init() {        // 计算可使用的最大内存

final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);        // 取可用内存空间的1/4作为缓存

final int cacheSize = maxMemory / 4;

mMemoryLruCache = new LruCache(cacheSize) {            @Override

protected int sizeOf(String key, String value) {                return value.getBytes().length;

}            @Override

protected void entryRemoved(boolean evicted, String key, String oldValue, String newValue) {                if (evicted) {                    if (mEvictedListener != null) {

mEvictedListener.handleEvictEntry(key, oldValue);

}

}

}

};

}    @Override

public String get(String key) {        return mMemoryLruCache.get(key);

}    @Override

public void put(String key, String value) {

mMemoryLruCache.put(key, value);

}    @Override

public boolean remove(String key) {        return Boolean.parseBoolean(mMemoryLruCache.remove(key));

}    /**

* called when mMemoryLruCache evict entrys,

* using by CacheManager.Strategy.MEMORY_FIRST

*/

public interface EvictedListener {        void handleEvictEntry(String evictKey, String evictValue);

}

2、文件级别的Disk缓存类实现

接下来我们需要写一个用于Disk缓存管理的类:DiskCache类,该类我们也实现Cache接口,该类的主要功能也是提供Disk缓存的读取和写入操作管理。/**

* Disk磁盘缓存类

* Created by caizhiming on 2015/12/4.

*/public class DiskCache implements Cache{    private DiskLruCache mDiskLruCache = null;    public DiskCache(Context context){

init(context);

}    /**

* 初始化 DiskLruCache

*/

public void init(Context context){        try {

File cacheDir = getDiskCacheDir(context, "http_cache");            if (!cacheDir.exists()) {

cacheDir.mkdirs();

}

Log.v("czm", "cache file=" + cacheDir.getAbsolutePath());

mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024);

} catch (IOException e) {

e.printStackTrace();

}

}

@Override    public String get(String key) {

String result = null;        try {

DiskLruCache.Snapshot snapShot = mDiskLruCache.get(hashKeyForDisk(key));            if (snapShot != null) {

result = snapShot.getString(0);                return result;

}

} catch (IOException e) {

e.printStackTrace();            return null;

}        return result;

}

@Override    public void put(String key, String value) {

DiskLruCache.Editor editor = null;        try {

editor = mDiskLruCache.edit(hashKeyForDisk(key));            if (editor != null) {

editor.set(0, value);

editor.commit();

}

mDiskLruCache.flush();

} catch (IOException e) {

e.printStackTrace();

}

}

@Override    public boolean remove(String key) {        try {            return mDiskLruCache.remove(hashKeyForDisk(key));

} catch (IOException e) {

e.printStackTrace();

}        return false;

}    public Bitmap getImageCache(String key){

Bitmap bitmap = null;        try {

DiskLruCache.Snapshot snapShot = mDiskLruCache.get(hashKeyForDisk(key));            if (snapShot != null) {

InputStream is = snapShot.getInputStream(0);

bitmap = BitmapFactory.decodeStream(is);                return bitmap;

}

} catch (IOException e) {

e.printStackTrace();

}        return bitmap;

}    public void putImageCache(final String key){        new Thread(new Runnable() {

@Override            public void run() {                try {

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

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

editor.commit();

} else {

editor.abort();

}

}

mDiskLruCache.flush();

} catch (IOException e) {

e.printStackTrace();

}

}

}).start();

}    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(), 8 * 1024);            out = new BufferedOutputStream(outputStream, 8 * 1024);            int b;            while ((b = in.read()) != -1) {                out.write(b);

}            return true;

} catch (final IOException e) {

e.printStackTrace();

} finally {            if (urlConnection != null) {

urlConnection.disconnect();

}

CloseUtils.closeCloseable(out);

CloseUtils.closeCloseable(in);

}        return false;

}    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 

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

sb.append('0');

}

sb.append(hex);

}        return sb.toString();

}    public File getDiskCacheDir(Context context, String uniqueName) {

String cachePath;        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())

|| !Environment.isExternalStorageRemovable()) {

cachePath = context.getExternalCacheDir().getPath();

} else {

cachePath = context.getCacheDir().getPath();

}        return new File(cachePath + File.separator + uniqueName);

}    public int getAppVersion(Context context) {        try {

PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);            return info.versionCode;

} catch (PackageManager.NameNotFoundException e) {

e.printStackTrace();

}        return 1;

}

}

3、搭建封装双缓存管理框架类XCCacheManager

有了上面的内存缓存类MemoryCache和Disk缓存类DiskCache,我们就可以搭建封装真正的缓存管理类XCCacheManager了。

(1) 首先我们采用线程池技术来实现多线程缓存的读写操作

这样可以提高程序的性能,同时能处理任务量比较大的并发读写操作。private static XCCacheManager mInstance = null;private Strategy mStrategy = Strategy.MEMORY_FIRST;//线程池private ExecutorService mExecutor = null;//内存缓存private MemoryCache mMemoryCache;//Disk缓存private DiskCache mDiskCache;/**

* 初始化 DiskLruCache

*/

private void init(Context context) {

mExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

mDiskCache = new DiskCache(context);

mMemoryCache = new MemoryCache();

}

(2)其次XCCacheManager管理类采用单例实现public static XCCacheManager getInstance(Context context, Strategy strategy) {    if (mInstance == null) {        synchronized (XCCacheManager.class) {            if (mInstance == null) {

mInstance = new XCCacheManager(context.getApplicationContext(), strategy);

}

}

} else {

mInstance.setStrategy(strategy);

}    return mInstance;

}

(3)缓存策略

这里我们定义了缓存策略,便于适应各种不同业务需求,可以灵活使用不同的策略enum Strategy {

MEMORY_ONLY(0), MEMORY_FIRST(1), DISK_ONLY(3);        int id;

Strategy(int id) {            this.id = id;

}

}

默认采用内存优先MEMORY_FIRST这种策略

(4)根据对应的策略从缓存中读取内容/**

* 从缓存中读取value

*/

public String readCache(final String key) {

Future ret = mExecutor.submit(new Callable() {

@Override            public String call() throws Exception {

String result = null;                switch (mStrategy) {                    case MEMORY_ONLY:

result = mMemoryCache.get(key);                        break;                    case MEMORY_FIRST:

result = mMemoryCache.get(key);                        if (result == null) {

result = mDiskCache.get(key);

}                        break;                    case DISK_ONLY:

result = mDiskCache.get(key);                        break;

}                return result;

}

});        try {            return ret.get();

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}        return null;

}

(5)将内容写入到缓存中/**

* 将value 写入到缓存中

*/

public void writeCache(final String key, final String value) {

mExecutor.submit(new Runnable() {

@Override            public void run() {                switch (mStrategy) {                    case MEMORY_FIRST:                        if (!mMemoryCache.hasEvictedListener()) {

mMemoryCache.setEvictedListener(new MemoryCache.EvictedListener() {

@Override                                public void handleEvictEntry(String evictKey, String evictValue) {

mDiskCache.put(evictKey, evictValue);

}

});

}

mMemoryCache.put(key, value);                        break;                    case MEMORY_ONLY:                        if (mMemoryCache.hasEvictedListener())

mMemoryCache.setEvictedListener(null);

mMemoryCache.put(key, value);                        break;                    case DISK_ONLY:

mDiskCache.put(key, value);                        break;

}

}

});

}

到此为止,框架的开发到此完成。希望对有需要的人有所帮助。

四、源码下载

GitHub地址:https://github.com/jczmdeveloper/XCCacheManager

打开App,阅读手记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值