ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Android4,移动端跨平台开发大型项目

2022-01-29 14:03:25  阅读:131  来源: 互联网

标签:大型项目 return Android4 cache 跨平台 key entry new null


int count;

while ((count = reader.read(buffer)) != -1) {

writer.write(buffer, 0, count);

}

return writer.toString();

} finally {

reader.close();

}

}

/**

* Returns the ASCII characters up to but not including the next “\r\n”, or

* “\n”.

*

* @throws java.io.EOFException if the stream is exhausted before the next newline

*     character.

*  读取输入流中返回的某行ASCII码字符

*/

public static String readAsciiLine(InputStream in) throws IOException {

// TODO: support UTF-8 here instead

StringBuilder result = new StringBuilder(80);

while (true) {

int c = in.read();

if (c == -1) {

throw new EOFException();

} else if (c == ‘\n’) {

break;

}

result.append((char) c);

}

int length = result.length();

if (length > 0 && result.charAt(length - 1) == ‘\r’) {

result.setLength(length - 1);

}

return result.toString();

}

/**

* Closes ‘closeable’, ignoring any checked exceptions. Does nothing if ‘closeable’ is null.

* closeable关闭

*/

public static void closeQuietly(Closeable closeable) {

if (closeable != null) {

try {

closeable.close();

} catch (RuntimeException rethrown) {

throw rethrown;

} catch (Exception ignored) {

}

}

}

/**

* Recursively delete everything in {@code dir}.

* 递归删除dir

*/

// TODO: this should specify paths as Strings rather than as Files

public static void deleteContents(File dir) throws IOException {

File[] files = dir.listFiles();

if (files == null) {

throw new IllegalArgumentException("not a directory: " + dir);

}

for (File file : files) {

if (file.isDirectory()) {

deleteContents(file);

}

if (!file.delete()) {

throw new IOException("failed to delete file: " + file);

}

}

}

/** This cache uses a single background thread to evict entries.

*  后台单线程回收entry

*/

private final ExecutorService executorService = new ThreadPoolExecutor(0, 1,

60L, TimeUnit.SECONDS, new LinkedBlockingQueue());

private final Callable cleanupCallable = new Callable() {

@Override public Void call() throws Exception {

synchronized (DiskLruCache.this) {

if (journalWriter == null) {

return null; // closed

}

trimToSize();//回收到满足maxsize

if (journalRebuildRequired()) {

rebuildJournal();

redundantOpCount = 0;

}

}

return null;

}

};

//构造器

private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {

this.directory = directory;

this.appVersion = appVersion;

this.journalFile = new File(directory, JOURNAL_FILE);

this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP);

this.valueCount = valueCount;

this.maxSize = maxSize;

}

/**

* Opens the cache in {@code directory}, creating a cache if none exists

* there.

* 创建cache

*

* @param directory a writable directory

* @param appVersion

* @param valueCount the number of values per cache entry. Must be positive.

* 每一个key相对应的value的数目

* @param maxSize the maximum number of bytes this cache should use to store

* @throws IOException if reading or writing the cache directory fails

*/

public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)

throws IOException {

if (maxSize <= 0) {//maxsize必须大于0

throw new IllegalArgumentException(“maxSize <= 0”);

}

if (valueCount <= 0) {//valuecount也必须大于0

throw new IllegalArgumentException(“valueCount <= 0”);

}

// prefer to pick up where we left off优先处理先前的cache

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创建一个空新的cache

directory.mkdirs();

cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);

cache.rebuildJournal();

return cache;

}

//读取日志信息

private void readJournal() throws IOException {

InputStream in = new BufferedInputStream(new FileInputStream(journalFile), IO_BUFFER_SIZE);

try {

String magic = readAsciiLine(in);

String version = readAsciiLine(in);

String appVersionString = readAsciiLine(in);

String valueCountString = readAsciiLine(in);

String blank = readAsciiLine(in);

if (!MAGIC.equals(magic)

|| !VERSION_1.equals(version)

|| !Integer.toString(appVersion).equals(appVersionString)

|| !Integer.toString(valueCount).equals(valueCountString)

|| !"".equals(blank)) {

throw new IOException(“unexpected journal header: [”

  • magic + ", " + version + ", " + valueCountString + ", " + blank + “]”);

}

while (true) {

try {

readJournalLine(readAsciiLine(in));//读取日志信息

} catch (EOFException endOfJournal) {

break;

}

}

} finally {

closeQuietly(in);//关闭输入流

}

}

//读取日志中某行日志信息

private void readJournalLine(String line) throws IOException {

String[] parts = line.split(" ");

if (parts.length < 2) {

throw new IOException("unexpected journal line: " + line);

}

String key = parts[1];

if (parts[0].equals(REMOVE) && parts.length == 2) {

lruEntries.remove(key);

return;

}

Entry entry = lruEntries.get(key);

if (entry == null) {

entry = new Entry(key);

lruEntries.put(key, entry);

}

if (parts[0].equals(CLEAN) && parts.length == 2 + valueCount) {

entry.readable = true;

entry.currentEditor = null;

entry.setLengths(copyOfRange(parts, 2, parts.length));

} else if (parts[0].equals(DIRTY) && parts.length == 2) {

entry.currentEditor = new Editor(entry);

} else if (parts[0].equals(READ) && parts.length == 2) {

// this work was already done by calling lruEntries.get()

} else {

throw new IOException("unexpected journal line: " + line);

}

}

/**

* Computes the initial size and collects garbage as a part of opening the

* cache. Dirty entries are assumed to be inconsistent and will be deleted.

* 处理日志

* 计算初始化cache的初始化大小和收集垃圾。Dirty entry假定不一致将会被删掉。

*/

private void processJournal() throws IOException {

deleteIfExists(journalFileTmp);//删除日志文件

for (Iterator i = lruEntries.values().iterator(); i.hasNext(); ) {

Entry entry = i.next();

if (entry.currentEditor == null) {

for (int t = 0; t < valueCount; t++) {

size += entry.lengths[t];

}

} else {

entry.currentEditor = null;

for (int t = 0; t < valueCount; t++) {

deleteIfExists(entry.getCleanFile(t));

deleteIfExists(entry.getDirtyFile(t));

}

i.remove();

}

}

}

/**

* Creates a new journal that omits redundant information. This replaces the

* current journal if it exists.

* 创建一个新的删掉冗余信息的日志。替换当前的日志

*/

private synchronized void rebuildJournal() throws IOException {

if (journalWriter != null) {

journalWriter.close();

}

Writer writer = new BufferedWriter(new FileWriter(journalFileTmp), IO_BUFFER_SIZE);

writer.write(MAGIC);

writer.write("\n");

writer.write(VERSION_1);

writer.write("\n");

writer.write(Integer.toString(appVersion));

writer.write("\n");

writer.write(Integer.toString(valueCount));

writer.write("\n");

writer.write("\n");

for (Entry entry : lruEntries.values()) {

if (entry.currentEditor != null) {

writer.write(DIRTY + ’ ’ + entry.key + ‘\n’);

} else {

writer.write(CLEAN + ’ ’ + entry.key + entry.getLengths() + ‘\n’);

}

}

writer.close();

journalFileTmp.renameTo(journalFile);

journalWriter = new BufferedWriter(new FileWriter(journalFile, true), IO_BUFFER_SIZE);

}

//文件若存在删除

private static void deleteIfExists(File file) throws IOException {

//        try {

//            Libcore.os.remove(file.getPath());

//        } catch (ErrnoException errnoException) {

//            if (errnoException.errno != OsConstants.ENOENT) {

//                throw errnoException.rethrowAsIOException();

//            }

//        }

if (file.exists() && !file.delete()) {

throw new IOException();

}

}

/**

* Returns a snapshot of the entry named {@code key}, or null if it doesn’t

* exist is not currently readable. If a value is returned, it is moved to

* the head of the LRU queue.

* 返回key对应的entry的snapshot,当key相应的entry不存在或者当前不可读时返回null。

* 如果返回相应的值,它就会被移动到LRU队列的头部。

*/

public synchronized Snapshot get(String key) throws IOException {

checkNotClosed();//检查cache是否已关闭

validateKey(key);//验证key格式的正确性

Entry entry = lruEntries.get(key);

if (entry == null) {

return null;

}

if (!entry.readable) {

return null;

}

/*

* Open all streams eagerly to guarantee that we see a single published

* snapshot. If we opened streams lazily then the streams could come

* from different edits.

*/

InputStream[] ins = new InputStream[valueCount];

try {

for (int i = 0; i < valueCount; i++) {

ins[i] = new FileInputStream(entry.getCleanFile(i));

}

} catch (FileNotFoundException e) {

// a file must have been deleted manually!

return null;

}

redundantOpCount++;

journalWriter.append(READ + ’ ’ + key + ‘\n’);

if (journalRebuildRequired()) {

executorService.submit(cleanupCallable);

}

return new Snapshot(key, entry.sequenceNumber, ins);

}

/**

* Returns an editor for the entry named {@code key}, or null if another

* edit is in progress.

*/

public Editor edit(String key) throws IOException {

return edit(key, ANY_SEQUENCE_NUMBER);

}

//有key和序列号生成一个editor

private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {

checkNotClosed();//检查cache关闭与否

validateKey(key);//验证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;

}

/**

* Returns the directory where this cache stores its data.

*/

public File getDirectory() {

return directory;

}

/**

* Returns the maximum number of bytes that this cache should use to store

* its data.

*/

public long maxSize() {

return maxSize;

}

/**

* Returns the number of bytes currently being used to store the values in

* this cache. This may be greater than the max size if a background

* deletion is pending.

*/

public synchronized long size() {

return size;

}

//完成Edit动作

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);

}

}

/**

* We only rebuild the journal when it will halve the size of the journal

* and eliminate at least 2000 ops.

* 当日志大小减半并且删掉至少2000项时重新构造日志

*/

private boolean journalRebuildRequired() {

final int REDUNDANT_OP_COMPACT_THRESHOLD = 2000;

return redundantOpCount >= REDUNDANT_OP_COMPACT_THRESHOLD

&& redundantOpCount >= lruEntries.size();

}

/**

* Drops the entry for {@code key} if it exists and can be removed. Entries

* actively being edited cannot be removed.

* 删除key相应的entry,被编辑的Entry不能被remove

* @return true if an entry was removed.

*/

public synchronized boolean remove(String key) throws IOException {

checkNotClosed();//检查cache是否已经关闭

validateKey(key);//验证key格式的正确性

Entry entry = lruEntries.get(key);

if (entry == null || entry.currentEditor != null) {

return false;

}

for (int i = 0; i < valueCount; i++) {

File file = entry.getCleanFile(i);

if (!file.delete()) {

throw new IOException("failed to delete " + file);

}

size -= entry.lengths[i];

entry.lengths[i] = 0;

}

redundantOpCount++;

journalWriter.append(REMOVE + ’ ’ + key + ‘\n’);

lruEntries.remove(key);

if (journalRebuildRequired()) {

executorService.submit(cleanupCallable);

}

return true;

}

/**

* Returns true if this cache has been closed.

* 判断cache是否已经关闭

*/

public boolean isClosed() {

return journalWriter == null;

}

//检查cache是否已经关闭

private void checkNotClosed() {

if (journalWriter == null) {

throw new IllegalStateException(“cache is closed”);

}

}

/**

* Force buffered operations to the filesystem.

*/

public synchronized void flush() throws IOException {

checkNotClosed();//检查cache是否关闭

trimToSize();//满足最大空间limit

journalWriter.flush();

}

/**

* Closes this cache. Stored values will remain on the filesystem.

* 关闭cache。

*/

public synchronized void close() throws IOException {

if (journalWriter == null) {

return; // already closed

}

for (Entry entry : new ArrayList(lruEntries.values())) {

if (entry.currentEditor != null) {

entry.currentEditor.abort();

}

}

trimToSize();

journalWriter.close();

journalWriter = null;

}

//回收删除某些entry到空间大小满足maxsize

private void trimToSize() throws IOException {

while (size > maxSize) {

//            Map.Entry<String, Entry> toEvict = lruEntries.eldest();

final Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next();

remove(toEvict.getKey());

}

}

/**

* Closes the cache and deletes all of its stored values. This will delete

* all files in the cache directory including files that weren’t created by

* the cache.

* 关闭删除cache

*/

public void delete() throws IOException {

close();

deleteContents(directory);

}

//验证key格式的正确性

private void validateKey(String key) {

if (key.contains(" “) || key.contains(”\n") || key.contains("\r")) {

throw new IllegalArgumentException(

“keys must not contain spaces or newlines: \”" + key + “\”");

}

}

//字符串形式读出输入流的内容

private static String inputStreamToString(InputStream in) throws IOException {

return readFully(new InputStreamReader(in, UTF_8));

}

/**

* A snapshot of the values for an entry.

* entry的快照

*/

public final class Snapshot implements Closeable {

private final String key;//key

private final long sequenceNumber;//序列号(同文件名称)

private final InputStream[] ins;//两个修改的文件输入流

private Snapshot(String key, long sequenceNumber, InputStream[] ins) {

this.key = key;

this.sequenceNumber = sequenceNumber;

this.ins = ins;

}

/**

* Returns an editor for this snapshot’s entry, or null if either the

* entry has changed since this snapshot was created or if another edit

* is in progress.

* 返回entry快照的editor,如果entry已经更新了或者另一个edit正在处理过程中返回null。

*/

public Editor edit() throws IOException {

return DiskLruCache.this.edit(key, sequenceNumber);

}

/**

* Returns the unbuffered stream with the value for {@code index}.

*/

public InputStream getInputStream(int index) {

return ins[index];

}

/**

* Returns the string value for {@code index}.

*/

public String getString(int index) throws IOException {

return inputStreamToString(getInputStream(index));

}

@Override public void close() {

for (InputStream in : ins) {

closeQuietly(in);

}

}

}

/**

* Edits the values for an entry.

* entry编辑器
final class Snapshot implements Closeable {

private final String key;//key

private final long sequenceNumber;//序列号(同文件名称)

private final InputStream[] ins;//两个修改的文件输入流

private Snapshot(String key, long sequenceNumber, InputStream[] ins) {

this.key = key;

this.sequenceNumber = sequenceNumber;

this.ins = ins;

}

/**

* Returns an editor for this snapshot’s entry, or null if either the

* entry has changed since this snapshot was created or if another edit

* is in progress.

* 返回entry快照的editor,如果entry已经更新了或者另一个edit正在处理过程中返回null。

*/

public Editor edit() throws IOException {

return DiskLruCache.this.edit(key, sequenceNumber);

}

/**

* Returns the unbuffered stream with the value for {@code index}.

*/

public InputStream getInputStream(int index) {

return ins[index];

}

/**

* Returns the string value for {@code index}.

*/

public String getString(int index) throws IOException {

return inputStreamToString(getInputStream(index));

}

@Override public void close() {

for (InputStream in : ins) {

closeQuietly(in);

}

}

}

/**

* Edits the values for an entry.

* entry编辑器

标签:大型项目,return,Android4,cache,跨平台,key,entry,new,null
来源: https://blog.csdn.net/m0_66155412/article/details/122742816

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有