DiskLruCache 源码解析

着手阅读DiskLruCache 源码无可厚非先去了解 DiskLruCache  这个框架的用法 见下面代码:

   File cacheDir = getDiskCacheDir(this, "cache");
            if (!cacheDir.exists()) {
                cacheDir.mkdirs();
            }
            mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(this), 1, 10 * 1024 * 1024);

代码中出现了 DiskLruCache open 方法:

 

    public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
            throws IOException {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        if (valueCount <= 0) {
            throw new IllegalArgumentException("valueCount <= 0");
        }

        // prefer to pick up where we left off
        DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
        if (cache.journalFile.exists()) {
            try {
                cache.readJournal();
                cache.processJournal();
                cache.journalWriter = new BufferedWriter(new FileWriter(cache.journalFile, true),
                        IO_BUFFER_SIZE);
                return cache;
            } catch (IOException journalIsCorrupt) {
//                System.logW("DiskLruCache " + directory + " is corrupt: "
//                        + journalIsCorrupt.getMessage() + ", removing");
                cache.delete();
            }
        }

        // create a new empty cache
        directory.mkdirs();
        cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
        cache.rebuildJournal();
        return cache;
    }
 public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)

open 方法的三个参数 directory 代表缓存的文件夹,appVersion ,valueCount 缓存的文件数一般是1

 

journalFile  是一个日志文件记录了对文件的读写删除等操作记录,格式如下

 libcore.io.DiskLruCache
   1
   100
    2

   CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
   DIRTY 335c4c6028171cfddfbaae1a9c313c52
   CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
   REMOVE 335c4c6028171cfddfbaae1a9c313c52
   DIRTY 1ab96a171faeeee38496d8b330771a7a
   CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
   READ 335c4c6028171cfddfbaae1a9c313c52
   READ 3400330d1dfc7f3f7f4b8d4d803dfcf6

 

DIRTY:标识 entry  即将被创建或者被更新 接下来执行 CLEAN 或者 REMOVE 操作

CLEAN:表示 缓存的entry 即成功发布或者即将被读取

READ:文件被读取

REMOVE:文件从缓存中被移除

代码中先创建一个journalFileTmp 临时文件,文件写入成功之后重命名为 journalFile 

日志文件创建成功接下来就可以调用 save 缓存方法了

  String key = hashKeyForDisk(imageUrl);
                    DiskLruCache.Editor editor = null;

                    editor = mDiskLruCache.edit(key);
                    if (editor != null) {
                        OutputStream outputStream = editor.newOutputStream(0);
                        if (downloadUrlToStream(imageUrl, outputStream)) {
                            editor.commit();
                        } else {
                            editor.abort();
                        }
                    }
                    //不该频繁的flush
                    mDiskLruCache.flush();

此段代码创建了 entry  第一次该缓存文件肯定是不存在的,所以edit 方法中肯定是创建了一个entry 以及对应的Editor 对象来操作entry 对象;在 DiskLruCache 框架中把每一个操作对象看成是一个entry 节点,包含了对应的key(url 访问地址的MD5的编码)以及length, 是否刻度readable,  还有一个Editor 对象用来操作 entry,

private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {
        checkNotClosed();
        validateKey(key);
        Entry entry = lruEntries.get(key);
        if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER
                && (entry == null || entry.sequenceNumber != expectedSequenceNumber)) {
            return null; // snapshot is stale
        }
        if (entry == null) {
            entry = new Entry(key);
            lruEntries.put(key, entry);
        } else if (entry.currentEditor != null) {
            return null; // another edit is in progress
        }

        Editor editor = new Editor(entry);
        entry.currentEditor = editor;

        // flush the journal before creating files to prevent file leaks
        journalWriter.write(DIRTY + ' ' + key + '\n');
        journalWriter.flush();
        return editor;
    }

既然上面的代码返回了一个Editor 对象,记下来我们就该保存了

    private synchronized void completeEdit(Editor editor, boolean success) throws IOException {
        Entry entry = editor.entry;
        if (entry.currentEditor != editor) {
            throw new IllegalStateException();
        }

        // if this edit is creating the entry for the first time, every index must have a value
        if (success && !entry.readable) {
            for (int i = 0; i < valueCount; i++) {
                if (!entry.getDirtyFile(i).exists()) {
                    editor.abort();
                    throw new IllegalStateException("edit didn't create file " + i);
                }
            }
        }

        for (int i = 0; i < valueCount; i++) {
            File dirty = entry.getDirtyFile(i);
            if (success) {
                if (dirty.exists()) {
                    File clean = entry.getCleanFile(i);
                    dirty.renameTo(clean);
                    long oldLength = entry.lengths[i];
                    long newLength = clean.length();
                    entry.lengths[i] = newLength;
                    size = size - oldLength + newLength;
                }
            } else {
                deleteIfExists(dirty);
            }
        }

        redundantOpCount++;
        entry.currentEditor = null;
        if (entry.readable | success) {
            entry.readable = true;
            journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
            if (success) {
                entry.sequenceNumber = nextSequenceNumber++;
            }
        } else {
            lruEntries.remove(entry.key);
            journalWriter.write(REMOVE + ' ' + entry.key + '\n');
        }

        if (size > maxSize || journalRebuildRequired()) {
            executorService.submit(cleanupCallable);
        }
    }

上面是不是用到了journalWriter 进行了写入CLEAN 操作。既然是缓存作用,那么代码中的size 就是用来计算 缓存文件的大小了。

 

文中 用LinkedHashMap 来记录缓存文件 具体的可参见 大神的 彻头彻尾理解 LinkedHashMap  https://blog.csdn.net/justloveyou_/article/details/71713781

 

下载地址:https://download.csdn.net/download/tiger10100/10569177

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值