您的位置:首页 > 其它

DiskLruCache

2015-06-04 21:42 260 查看

DiskLruCache

非Google官方编写,但获得官方认证

https://github.com/JakeWharton/DiskLruCache

compile 'com.jakewharton:disklrucache:2.0.2'


使用方法

构造函数私有,只能通过open() 方法创建实例

/sdcard/Android/data/package name/cache

/data/data/package name/cache

public static DiskLruCache open(
File directory, // 存放路径
int appVersion, // 当前应用的版本号,每当版本号改变缓存路径下的数据都会被清除掉
int valueCount, // 同一个key可以对用多少个缓存文件,一般传1
long maxSize    // 最多可以缓存多少字节 Integer.MAX_VALUE
){}


写入 Edit

DiskLruCache.Editor edit = diskLruCache.edit("cache_1");    // key,对应文件cache_1.0
OutputStream os = edit.newOutputStream(0);  // 对应1个key可以缓存多个文件
// 流对拷...
edit.commit();  // edit.abort();


读取 Snapshot 此时对该数据进行更新和删除对次没有影响

DiskLruCache.Snapshot snapshot = diskLruCache.get("cache_1");
InputStream is = snapshot.getInputStream(0);


删除

diskLruCache.remove("cache_1");


清空

diskLruCache.delete();


原理

概述

---get() ---> Snapshot --- getInputStream() ---> InputStream
|
DiskLruCache.open()/delete()
|
--- edit() ---> Editor --- newOutputStream() ---> OutputStrem


journal

libcore.io.DiskLruCache

1

1

1

DIRTY cache_1

CLEAN cache_1 107

REMOVE cache_1

open() 的时候如果存在journal文件,readJournal() 一行行读取

String magic = reader.readLine();   // libcore.io.DiskLruCache:固定值
String version = reader.readLine(); // 1:DiskLruCache 版本号
String appVersionString = reader.readLine();        // 1:传入的App版本号
String valueCountString = reader.readLine();        // 1:传入的一个key对应几个文件
String blank = reader.readLine();


如果发现以上这些元素和open() 时传入的参数不一致,就抛出IOE,open() 中捕获后会清空该目录delete() ,并重建rebuildJournal()

private Writer journalWriter;


get()

journalWriter.append(READ + ' ' + key + '\n');


commit()

journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');


remove()

journalWriter.append(REMOVE + ' ' + key + '\n');


LinkedHashMap

private final LinkedHashMap<String, Entry> lruEntries =
new LinkedHashMap<String, Entry>(0, 0.75f, true);

private final class Entry {

private final String key; // getCacheFile(); getDirtyFile();

private final long[] lengths;

private boolean readable;

private Editor currentEditor;

private long sequenceNumber;
}


edit() 的时候先new Entry() 放入容器,再创建Editor(),edit写入的是dirtyFile(key + “.” + i + “.tmp”)

commit() 的时候把dirtyFile从命名为cacheFile(key + “.” + i),同时将entry关联的editor 置为null,切断关联entry.currentEditor = null;

// 部分代码
public synchronized Snapshot get(String key) throws IOException {
Entry entry = lruEntries.get(key);
InputStream[] ins = new InputStream[valueCount];
for (int i = 0; i < valueCount; i++) {
ins[i] = new FileInputStream(entry.getCleanFile(i));
}
return new Snapshot(key, entry.sequenceNumber, ins, entry.lengths);
}

public final class Snapshot implements Closeable {
private final String key;
private final long sequenceNumber;
private final InputStream[] ins;
private final long[] lengths;

public InputStream getInputStream(int index) {
return ins[index];
}

public void close() {
for (InputStream in : ins) {
Util.closeQuietly(in);
}
}
}


清理工作

写入日志的通知,判断是否需要清理日志文件和集合对象

// 对应日志的次数,每写入、删除、读取一次都+1,直到2000时对journal重构一次,避免文件过大
private int redundantOpCount;

// 清理线程
final ThreadPoolExecutor executorService =
new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

// 清理条件
private boolean journalRebuildRequired() {
final int redundantOpCompactThreshold = 2000;
return redundantOpCount >= redundantOpCompactThreshold //
&& redundantOpCount >= lruEntries.size();
}

// 具体的清理工作
public Void call() throws Exception {
synchronized (DiskLruCache.this) {
if (journalWriter == null) {
return null; // Closed.
}
trimToSize();
if (journalRebuildRequired()) {
rebuildJournal();
redundantOpCount = 0;
}
}
return null;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: