ASimpleCache学习笔记

来源:互联网 发布:高考志愿填报软件 编辑:程序博客网 时间:2024/06/12 14:45
开源缓存框架ASimpleCache调研学习:
源码网址:https://github.com/yangfuhai/ASimpleCache
二级缓存定义:


当Android端需要获得数据时比如获取网络中的图片,我们首先从内存中查找(按键查找),内存中没有的再从磁盘文件或sqlite中去查找,若磁盘中也没有才通过网络获取;当获得来自网络的数据,就以key-value对的方式先缓存到内存(一级缓存),同时缓存到文件或sqlite中(二级缓存)。注意:内存缓存会造成堆内存泄露,所有一级缓存通常要严格控制缓存的大小,一般控制在系统内存的1/4。




##1、如何使用 ASimpleCache? 如下是github上给出的一个简单例子:


ACache mCache = ACache.get(this);
mCache.put("test_key1", "test value");
mCache.put("test_key2", "test value", 10);//保存10秒,如果超过10秒去获取这个key,将为null
mCache.put("test_key3", "test value", 2 * ACache.TIME_DAY);//保存两天,如果超过两天去获取这个key,将为null


获取数据
ACache mCache = ACache.get(this);
String value = mCache.getAsString("test_key1");


##2,它只有一个类,约800行,可以缓存数据类型有:普通的字符串、JsonObject、JsonArray、Bitmap、Drawable、序列化的java对象,和 byte数据;还可以设置缓存大小和缓存时间。


##3,
####3.1
ACache采用典型的单例实现,初始化使用get()方法,共有5个get()方法可以获取ACache对象,但最终都会调用到public static ACache get(File cacheDir, long max_zise, int max_count) 这个方法。
方法体如下:
public static ACache get(File cacheDir, long max_zise, int max_count) {
        ACache manager = mInstanceMap.get(cacheDir.getAbsoluteFile() + myPid());
        if (manager == null) {
            manager = new ACache(cacheDir, max_zise, max_count);
            mInstanceMap.put(cacheDir.getAbsolutePath() + myPid(), manager);
        }
        return manager;
    }


这个方法中,根据缓存目录和当前的进程id获取Acache对象,如果没有,则会构造一个ACache对象并保存到mInstanceMap中。Acache为不同进程设置了不同的缓存文件夹。通过mInstanceMap来管理不同进程的缓存实例。


####3.2 如何构造ACache对象的?
private ACache(File cacheDir, long max_size, int max_count) {
        if (!cacheDir.exists() && !cacheDir.mkdirs()) {
            throw new RuntimeException("can't make dirs in "
                    + cacheDir.getAbsolutePath());
        }
        mCache = new ACacheManager(cacheDir, max_size, max_count);
}


构造ACache对象的方法中,会创建缓存的目录,然后调用ACacheManager的构造,初始化了变量mCache。ACacheManager内部简单的实现了LRU,Acache则为ACacheManager提供一层封装,负责对外提供接口。


####3.3 ACacheManager构造方法
private ACacheManager(File cacheDir, long sizeLimit, int countLimit) {
            this.cacheDir = cacheDir;
            this.sizeLimit = sizeLimit;
            this.countLimit = countLimit;
            cacheSize = new AtomicLong();
            cacheCount = new AtomicInteger();
            calculateCacheSizeAndCacheCount();
        }
在ACacheManager类中,使用Map<File, Long> lastUsageDates存储文件最近的使用时间,在缓存大小大于sizeLimit,或者缓存数量大于countLimit时,会根据lastUsageDates保存的时间,删除最近最少使用的缓存文件。




##4 mCache.put("test_key1", "test value");究竟做了什么工作?


public void put(String key, String value) {
        File file = mCache.newFile(key);
        BufferedWriter out = null;
        try {
            out = new BufferedWriter(new FileWriter(file), 1024);
            out.write(value);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.flush();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            mCache.put(file);
        }
    }


####4.1 mCache.newFile(key); 首先通过ACacheManager对象mCache在默认缓存目录或者自己设定的缓存目录下,以key的hashcode为名,创建缓存文件。
private File newFile(String key) {
            return new File(cacheDir, key.hashCode() + "");
        }


####4.2 把put方法传入的value值写入刚刚创建的缓存文件中。
####4.3 在finally里面调用mCache.put(file);,更新ACacheManager中的cacheCount,cacheSize以及lastUsageDates中保存的文件最新修改时间。
private void put(File file) {
            int curCacheCount = cacheCount.get();
            while (curCacheCount + 1 > countLimit) {
                long freedSize = removeNext();
                cacheSize.addAndGet(-freedSize);


                curCacheCount = cacheCount.addAndGet(-1);
            }
            cacheCount.addAndGet(1);


            long valueSize = calculateSize(file);
            long curCacheSize = cacheSize.get();
            while (curCacheSize + valueSize > sizeLimit) {
                long freedSize = removeNext();
                curCacheSize = cacheSize.addAndGet(-freedSize);
            }
            cacheSize.addAndGet(valueSize);


            Long currentTime = System.currentTimeMillis();
            file.setLastModified(currentTime);
            lastUsageDates.put(file, currentTime);
        }




##5 如何从缓存获取数据的?
public String getAsString(String key) {
        File file = mCache.get(key);
        if (!file.exists())
            return null;
        boolean removeFile = false;
        BufferedReader in = null;
        try {
            in = new BufferedReader(new FileReader(file));
            String readString = "";
            String currentLine;
            while ((currentLine = in.readLine()) != null) {
                readString += currentLine;
            }
            if (!Utils.isDue(readString)) {
                return Utils.clearDateInfo(readString);
            } else {
                removeFile = true;
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (removeFile)
                remove(key);
        }
    }


####5.1 首先调用ACacheManager对象mCache.get(key);,返回file对象,同时更新file的最新修改时间,以便缓存满时清除缓存。
private File get(String key) {
            File file = newFile(key);
            Long currentTime = System.currentTimeMillis();
            file.setLastModified(currentTime);
            lastUsageDates.put(file, currentTime);


            return file;
        }


####5.2 接着有个非空判断,判断文件是否存在,个人认为似乎没用,因为mCache.get(key)中,直接new了一个file。


####5.3 然后就是从缓存文件中读取数据,判断若没有过期,则返回value;否则返回null,并且在finally中删除过期的缓存文件。


##6 可以设置缓存有效时间是如何实现的?
####6.1 在put的时候,将当前的时间和缓存的有效时间以一定的格式拼接在要保存的value的前面。
public void put(String key, String value, int saveTime) {
        put(key, Utils.newStringWithDateInfo(saveTime, value));
    }
####6.2 在get的时候,去掉时间信息,返回保存的原始value。
if (!Utils.isDue(readString)) {
                return Utils.clearDateInfo(readString);
                ......


##7 网上很多资料描述,ASimpleCache将数据同时存入一级缓存(内存Map)和二级缓存(文件)中。但是看了源码,发现ASimpleCache实现的只是二级缓存,其实并没有保存到内存中。


##8 自己网上搜索了些资料,整理了一下,目前实现了一个能同时存入一级缓存和二级缓存的ACache。







原创粉丝点击