Android4.1.1中的LruDiskCache源码

android 系统自带分享功能之pdf分享并且打开 公司做的app有一个分享pdf文件的功能,产品经理明说要用系统自带的分享。 首先在AndroidManifest.xml中配置: activity android:name="com.artifex.mupdfdemo.MedlivePDFActivity" android:configChanges="orientation|screenSize|keyboardHidd 阅读详情
  1. /*
  2.  * Copyright (C) 2011 The Android Open Source Project
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  *      http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */

  16. package libcore.io;

  17. import java.io.BufferedInputStream;
  18. import java.io.BufferedWriter;
  19. import java.io.Closeable;
  20. import java.io.EOFException;
  21. import java.io.File;
  22. import java.io.FileInputStream;
  23. import java.io.FileNotFoundException;
  24. import java.io.FileOutputStream;
  25. import java.io.FileWriter;
  26. import java.io.FilterOutputStream;
  27. import java.io.IOException;
  28. import java.io.InputStream;
  29. import java.io.InputStreamReader;
  30. import java.io.OutputStream;
  31. import java.io.OutputStreamWriter;
  32. import java.io.Writer;
  33. import java.nio.charset.Charsets;
  34. import java.util.ArrayList;
  35. import java.util.Arrays;
  36. import java.util.Iterator;
  37. import java.util.LinkedHashMap;
  38. import java.util.Map;
  39. import java.util.concurrent.Callable;
  40. import java.util.concurrent.ExecutorService;
  41. import java.util.concurrent.LinkedBlockingQueue;
  42. import java.util.concurrent.ThreadPoolExecutor;
  43. import java.util.concurrent.TimeUnit;

  44. /**
  45.  * A cache that uses a bounded amount of space on a filesystem. Each cache
  46.  * entry has a string key and a fixed number of values. Values are byte
  47.  * sequences, accessible as streams or files. Each value must be between {@code
  48.  * 0} and {@code Integer.MAX_VALUE} bytes in length.
  49.  *
  50.  * <p>The cache stores its data in a directory on the filesystem. This
  51.  * directory must be exclusive to the cache; the cache may delete or overwrite
  52.  * files from its directory. It is an error for multiple processes to use the
  53.  * same cache directory at the same time.
  54.  *
  55.  * <p>This cache limits the number of bytes that it will store on the
  56.  * filesystem. When the number of stored bytes exceeds the limit, the cache will
  57.  * remove entries in the background until the limit is satisfied. The limit is
  58.  * not strict: the cache may temporarily exceed it while waiting for files to be
  59.  * deleted. The limit does not include filesystem overhead or the cache
  60.  * journal so space-sensitive applications should set a conservative limit.
  61.  *
  62.  * <p>Clients call {@link #edit} to create or update the values of an entry. An
  63.  * entry may have only one editor at one time; if a value is not available to be
  64.  * edited then {@link #edit} will return null.
  65.  * <ul>
  66.  *     <li>When an entry is being <strong>created</strong> it is necessary to
  67.  *         supply a full set of values; the empty value should be used as a
  68.  *         placeholder if necessary.
  69.  *     <li>When an entry is being <strong>edited</strong>, it is not necessary
  70.  *         to supply data for every value; values default to their previous
  71.  *         value.
  72.  * </ul>
  73.  * Every {@link #edit} call must be matched by a call to {@link Editor#commit}
  74.  * or {@link Editor#abort}. Committing is atomic: a read observes the full set
  75.  * of values as they were before or after the commit, but never a mix of values.
  76.  *
  77.  * <p>Clients call {@link #get} to read a snapshot of an entry. The read will
  78.  * observe the value at the time that {@link #get} was called. Updates and
  79.  * removals after the call do not impact ongoing reads.
  80.  *
  81.  * <p>This class is tolerant of some I/O errors. If files are missing from the
  82.  * filesystem, the corresponding entries will be dropped from the cache. If
  83.  * an error occurs while writing a cache value, the edit will fail silently.
  84.  * Callers should handle other problems by catching {@code IOException} and
  85.  * responding appropriately.
  86.  */
  87. public final class DiskLruCache implements Closeable {
  88.     static final String JOURNAL_FILE = "journal";
  89.     static final String JOURNAL_FILE_TMP = "journal.tmp";
  90.     static final String MAGIC = "libcore.io.DiskLruCache";
  91.     static final String VERSION_1 = "1";
  92.     static final long ANY_SEQUENCE_NUMBER = -1;
  93.     private static final String CLEAN = "CLEAN";
  94.     private static final String DIRTY = "DIRTY";
  95.     private static final String REMOVE = "REMOVE";
  96.     private static final String READ = "READ";

  97.     /*
  98.      * This cache uses a journal file named "journal". A typical journal file
  99.      * looks like this:
  100.      *     libcore.io.DiskLruCache
  101.      *     1
  102.      *     100
  103.      *     2
  104.      *
  105.      *     CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
  106.      *     DIRTY 335c4c6028171cfddfbaae1a9c313c52
  107.      *     CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
  108.      *     REMOVE 335c4c6028171cfddfbaae1a9c313c52
  109.      *     DIRTY 1ab96a171faeeee38496d8b330771a7a
  110.      *     CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
  111.      *     READ 335c4c6028171cfddfbaae1a9c313c52
  112.      *     READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
  113.      *
  114.      * The first five lines of the journal form its header. They are the
  115.      * constant string "libcore.io.DiskLruCache", the disk cache's version,
  116.      * the application's version, the value count, and a blank line.
  117.      *
  118.      * Each of the subsequent lines in the file is a record of the state of a
  119.      * cache entry. Each line contains space-separated values: a state, a key,
  120.      * and optional state-specific values.
  121.      *   o DIRTY lines track that an entry is actively being created or updated.
  122.      *     Every successful DIRTY action should be followed by a CLEAN or REMOVE
  123.      *     action. DIRTY lines without a matching CLEAN or REMOVE indicate that
  124.      *     temporary files may need to be deleted.
  125.      *   o CLEAN lines track a cache entry that has been successfully published
  126.      *     and may be read. A publish line is followed by the lengths of each of
  127.      *     its values.
  128.      *   o READ lines track accesses for LRU.
  129.      *   o REMOVE lines track entries that have been deleted.
  130.      *
  131.      * The journal file is appended to as cache operations occur. The journal may
  132.      * occasionally be compacted by dropping redundant lines. A temporary file named
  133.      * "journal.tmp" will be used during compaction; that file should be deleted if
  134.      * it exists when the cache is opened.
  135.      */

  136.     private final File directory;
  137.     private final File journalFile;
  138.     private final File journalFileTmp;
  139.     private final int appVersion;
  140.     private final long maxSize;
  141.     private final int valueCount;
  142.     private long size = 0;
  143.     private Writer journalWriter;
  144.     private final LinkedHashMap<String, Entry> lruEntries
  145.             = new LinkedHashMap<String, Entry>(0, 0.75f, true);
  146.     private int redundantOpCount;

  147.     /**
  148.      * To differentiate between old and current snapshots, each entry is given
  149.      * a sequence number each time an edit is committed. A snapshot is stale if
  150.      * its sequence number is not equal to its entry's sequence number.
  151.      */
  152.     private long nextSequenceNumber = 0;

  153.     /** This cache uses a single background thread to evict entries. */
  154.     private final ExecutorService executorService = new ThreadPoolExecutor(0, 1,
  155.             60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
  156.     private final Callable<Void> cleanupCallable = new Callable<Void>() {
  157.         @Override public Void call() throws Exception {
  158.             synchronized (DiskLruCache.this) {
  159.                 if (journalWriter == null) {
  160.                     return null; // closed
  161.                 }
  162.                 trimToSize();
  163.                 if (journalRebuildRequired()) {
  164.                     rebuildJournal();
  165.                     redundantOpCount = 0;
  166.                 }
  167.             }
  168.             return null;
  169.         }
  170.     };

  171.     private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {
  172.         this.directory = directory;
  173.         this.appVersion = appVersion;
  174.         this.journalFile = new File(directory, JOURNAL_FILE);
  175.         this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP);
  176.         this.valueCount = valueCount;
  177.         this.maxSize = maxSize;
  178.     }

  179.     /**
  180.      * Opens the cache in {@code directory}, creating a cache if none exists
  181.      * there.
  182.      *
  183.      * @param directory a writable directory
  184.      * @param appVersion
  185.      * @param valueCount the number of values per cache entry. Must be positive.
  186.      * @param maxSize the maximum number of bytes this cache should use to store
  187.      * @throws IOException if reading or writing the cache directory fails
  188.      */
  189.     public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
  190.             throws IOException {
  191.         if (maxSize <= 0) {
  192.             throw new IllegalArgumentException("maxSize <= 0");
  193.         }
  194.         if (valueCount <= 0) {
  195.             throw new IllegalArgumentException("valueCount <= 0");
  196.         }

  197.         // prefer to pick up where we left off
  198.         DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
  199.         if (cache.journalFile.exists()) {
  200.             try {
  201.                 cache.readJournal();
  202.                 cache.processJournal();
  203.                 cache.journalWriter = new BufferedWriter(new FileWriter(cache.journalFile, true));
  204.                 return cache;
  205.             } catch (IOException journalIsCorrupt) {
  206.                 System.logW("DiskLruCache " + directory + " is corrupt: "
  207.                         + journalIsCorrupt.getMessage() + ", removing");
  208.                 cache.delete();
  209.             }
  210.         }

  211.         // create a new empty cache
  212.         directory.mkdirs();
  213.         cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
  214.         cache.rebuildJournal();
  215.         return cache;
  216.     }

  217.     private void readJournal() throws IOException {
  218.         InputStream in = new BufferedInputStream(new FileInputStream(journalFile));
  219.         try {
  220.             String magic = Streams.readAsciiLine(in);
  221.             String version = Streams.readAsciiLine(in);
  222.             String appVersionString = Streams.readAsciiLine(in);
  223.             String valueCountString = Streams.readAsciiLine(in);
  224.             String blank = Streams.readAsciiLine(in);
  225.             if (!MAGIC.equals(magic)
  226.                     || !VERSION_1.equals(version)
  227.                     || !Integer.toString(appVersion).equals(appVersionString)
  228.                     || !Integer.toString(valueCount).equals(valueCountString)
  229.                     || !"".equals(blank)) {
  230.                 throw new IOException("unexpected journal header: ["
  231.                         + magic + ", " + version + ", " + valueCountString + ", " + blank + "]");
  232.             }

  233.             while (true) {
  234.                 try {
  235.                     readJournalLine(Streams.readAsciiLine(in));
  236.                 } catch (EOFException endOfJournal) {
  237.                     break;
  238.                 }
  239.             }
  240.         } finally {
  241.             IoUtils.closeQuietly(in);
  242.         }
  243.     }

  244.     private void readJournalLine(String line) throws IOException {
  245.         String[] parts = line.split(" ");
  246.         if (parts.length < 2) {
  247.             throw new IOException("unexpected journal line: " + line);
  248.         }

  249.         String key = parts[1];
  250.         if (parts[0].equals(REMOVE) && parts.length == 2) {
  251.             lruEntries.remove(key);
  252.             return;
  253.         }

  254.         Entry entry = lruEntries.get(key);
  255.         if (entry == null) {
  256.             entry = new Entry(key);
  257.             lruEntries.put(key, entry);
  258.         }

  259.         if (parts[0].equals(CLEAN) && parts.length == 2 + valueCount) {
  260.             entry.readable = true;
  261.             entry.currentEditor = null;
  262.             entry.setLengths(Arrays.copyOfRange(parts, 2, parts.length));
  263.         } else if (parts[0].equals(DIRTY) && parts.length == 2) {
  264.             entry.currentEditor = new Editor(entry);
  265.         } else if (parts[0].equals(READ) && parts.length == 2) {
  266.             // this work was already done by calling lruEntries.get()
  267.         } else {
  268.             throw new IOException("unexpected journal line: " + line);
  269.         }
  270.     }

  271.     /**
  272.      * Computes the initial size and collects garbage as a part of opening the
  273.      * cache. Dirty entries are assumed to be inconsistent and will be deleted.
  274.      */
  275.     private void processJournal() throws IOException {
  276.         deleteIfExists(journalFileTmp);
  277.         for (Iterator<Entry> i = lruEntries.values().iterator(); i.hasNext(); ) {
  278.             Entry entry = i.next();
  279.             if (entry.currentEditor == null) {
  280.                 for (int t = 0; t < valueCount; t++) {
  281.                     size += entry.lengths[t];
  282.                 }
  283.             } else {
  284.                 entry.currentEditor = null;
  285.                 for (int t = 0; t < valueCount; t++) {
  286.                     deleteIfExists(entry.getCleanFile(t));
  287.                     deleteIfExists(entry.getDirtyFile(t));
  288.                 }
  289.                 i.remove();
  290.             }
  291.         }
  292.     }

  293.     /**
  294.      * Creates a new journal that omits redundant information. This replaces the
  295.      * current journal if it exists.
  296.      */
  297.     private synchronized void rebuildJournal() throws IOException {
  298.         if (journalWriter != null) {
  299.             journalWriter.close();
  300.         }

  301.         Writer writer = new BufferedWriter(new FileWriter(journalFileTmp));
  302.         writer.write(MAGIC);
  303.         writer.write("\n");
  304.         writer.write(VERSION_1);
  305.         writer.write("\n");
  306.         writer.write(Integer.toString(appVersion));
  307.         writer.write("\n");
  308.         writer.write(Integer.toString(valueCount));
  309.         writer.write("\n");
  310.         writer.write("\n");

  311.         for (Entry entry : lruEntries.values()) {
  312.             if (entry.currentEditor != null) {
  313.                 writer.write(DIRTY + ' ' + entry.key + '\n');
  314.             } else {
  315.                 writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
  316.             }
  317.         }

  318.         writer.close();
  319.         journalFileTmp.renameTo(journalFile);
  320.         journalWriter = new BufferedWriter(new FileWriter(journalFile, true));
  321.     }

  322.     private static void deleteIfExists(File file) throws IOException {
  323.         try {
  324.             Libcore.os.remove(file.getPath());
  325.         } catch (ErrnoException errnoException) {
  326.             if (errnoException.errno != OsConstants.ENOENT) {
  327.                 throw errnoException.rethrowAsIOException();
  328.             }
  329.         }
  330.     }

  331.     /**
  332.      * Returns a snapshot of the entry named {@code key}, or null if it doesn't
  333.      * exist is not currently readable. If a value is returned, it is moved to
  334.      * the head of the LRU queue.
  335.      */
  336.     public synchronized Snapshot get(String key) throws IOException {
  337.         checkNotClosed();
  338.         validateKey(key);
  339.         Entry entry = lruEntries.get(key);
  340.         if (entry == null) {
  341.             return null;
  342.         }

  343.         if (!entry.readable) {
  344.             return null;
  345.         }

  346.         /*
  347.          * Open all streams eagerly to guarantee that we see a single published
  348.          * snapshot. If we opened streams lazily then the streams could come
  349.          * from different edits.
  350.          */
  351.         InputStream[] ins = new InputStream[valueCount];
  352.         try {
  353.             for (int i = 0; i < valueCount; i++) {
  354.                 ins[i] = new FileInputStream(entry.getCleanFile(i));
  355.             }
  356.         } catch (FileNotFoundException e) {
  357.             // a file must have been deleted manually!
  358.             return null;
  359.         }

  360.         redundantOpCount++;
  361.         journalWriter.append(READ + ' ' + key + '\n');
  362.         if (journalRebuildRequired()) {
  363.             executorService.submit(cleanupCallable);
  364.         }

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

  367.     /**
  368.      * Returns an editor for the entry named {@code key}, or null if another
  369.      * edit is in progress.
  370.      */
  371.     public Editor edit(String key) throws IOException {
  372.         return edit(key, ANY_SEQUENCE_NUMBER);
  373.     }

  374.     private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {
  375.         checkNotClosed();
  376.         validateKey(key);
  377.         Entry entry = lruEntries.get(key);
  378.         if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER
  379.                 && (entry == null || entry.sequenceNumber != expectedSequenceNumber)) {
  380.             return null; // snapshot is stale
  381.         }
  382.         if (entry == null) {
  383.             entry = new Entry(key);
  384.             lruEntries.put(key, entry);
  385.         } else if (entry.currentEditor != null) {
  386.             return null; // another edit is in progress
  387.         }

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

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

  395.     /**
  396.      * Returns the directory where this cache stores its data.
  397.      */
  398.     public File getDirectory() {
  399.         return directory;
  400.     }

  401.     /**
  402.      * Returns the maximum number of bytes that this cache should use to store
  403.      * its data.
  404.      */
  405.     public long maxSize() {
  406.         return maxSize;
  407.     }

  408.     /**
  409.      * Returns the number of bytes currently being used to store the values in
  410.      * this cache. This may be greater than the max size if a background
  411.      * deletion is pending.
  412.      */
  413.     public synchronized long size() {
  414.         return size;
  415.     }

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

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

  430.         for (int i = 0; i < valueCount; i++) {
  431.             File dirty = entry.getDirtyFile(i);
  432.             if (success) {
  433.                 if (dirty.exists()) {
  434.                     File clean = entry.getCleanFile(i);
  435.                     dirty.renameTo(clean);
  436.                     long oldLength = entry.lengths[i];
  437.                     long newLength = clean.length();
  438.                     entry.lengths[i] = newLength;
  439.                     size = size - oldLength + newLength;
  440.                 }
  441.             } else {
  442.                 deleteIfExists(dirty);
  443.             }
  444.         }

  445.         redundantOpCount++;
  446.         entry.currentEditor = null;
  447.         if (entry.readable | success) {
  448.             entry.readable = true;
  449.             journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
  450.             if (success) {
  451.                 entry.sequenceNumber = nextSequenceNumber++;
  452.             }
  453.         } else {
  454.             lruEntries.remove(entry.key);
  455.             journalWriter.write(REMOVE + ' ' + entry.key + '\n');
  456.         }

  457.         if (size > maxSize || journalRebuildRequired()) {
  458.             executorService.submit(cleanupCallable);
  459.         }
  460.     }

  461.     /**
  462.      * We only rebuild the journal when it will halve the size of the journal
  463.      * and eliminate at least 2000 ops.
  464.      */
  465.     private boolean journalRebuildRequired() {
  466.         final int REDUNDANT_OP_COMPACT_THRESHOLD = 2000;
  467.         return redundantOpCount >= REDUNDANT_OP_COMPACT_THRESHOLD
  468.                 && redundantOpCount >= lruEntries.size();
  469.     }

  470.     /**
  471.      * Drops the entry for {@code key} if it exists and can be removed. Entries
  472.      * actively being edited cannot be removed.
  473.      *
  474.      * @return true if an entry was removed.
  475.      */
  476.     public synchronized boolean remove(String key) throws IOException {
  477.         checkNotClosed();
  478.         validateKey(key);
  479.         Entry entry = lruEntries.get(key);
  480.         if (entry == null || entry.currentEditor != null) {
  481.             return false;
  482.         }

  483.         for (int i = 0; i < valueCount; i++) {
  484.             File file = entry.getCleanFile(i);
  485.             if (!file.delete()) {
  486.                 throw new IOException("failed to delete " + file);
  487.             }
  488.             size -= entry.lengths[i];
  489.             entry.lengths[i] = 0;
  490.         }

  491.         redundantOpCount++;
  492.         journalWriter.append(REMOVE + ' ' + key + '\n');
  493.         lruEntries.remove(key);

  494.         if (journalRebuildRequired()) {
  495.             executorService.submit(cleanupCallable);
  496.         }

  497.         return true;
  498.     }

  499.     /**
  500.      * Returns true if this cache has been closed.
  501.      */
  502.     public boolean isClosed() {
  503.         return journalWriter == null;
  504.     }

  505.     private void checkNotClosed() {
  506.         if (journalWriter == null) {
  507.             throw new IllegalStateException("cache is closed");
  508.         }
  509.     }

  510.     /**
  511.      * Force buffered operations to the filesystem.
  512.      */
  513.     public synchronized void flush() throws IOException {
  514.         checkNotClosed();
  515.         trimToSize();
  516.         journalWriter.flush();
  517.     }

  518.     /**
  519.      * Closes this cache. Stored values will remain on the filesystem.
  520.      */
  521.     public synchronized void close() throws IOException {
  522.         if (journalWriter == null) {
  523.             return; // already closed
  524.         }
  525.         for (Entry entry : new ArrayList<Entry>(lruEntries.values())) {
  526.             if (entry.currentEditor != null) {
  527.                 entry.currentEditor.abort();
  528.             }
  529.         }
  530.         trimToSize();
  531.         journalWriter.close();
  532.         journalWriter = null;
  533.     }

  534.     private void trimToSize() throws IOException {
  535.         while (size > maxSize) {
  536.             Map.Entry<String, Entry> toEvict = lruEntries.eldest();
  537.             remove(toEvict.getKey());
  538.         }
  539.     }

  540.     /**
  541.      * Closes the cache and deletes all of its stored values. This will delete
  542.      * all files in the cache directory including files that weren't created by
  543.      * the cache.
  544.      */
  545.     public void delete() throws IOException {
  546.         close();
  547.         IoUtils.deleteContents(directory);
  548.     }

  549.     private void validateKey(String key) {
  550.         if (key.contains(" ") || key.contains("\n") || key.contains("\r")) {
  551.             throw new IllegalArgumentException(
  552.                     "keys must not contain spaces or newlines: \"" + key + "\"");
  553.         }
  554.     }

  555.     private static String inputStreamToString(InputStream in) throws IOException {
  556.         return Streams.readFully(new InputStreamReader(in, Charsets.UTF_8));
  557.     }

  558.     /**
  559.      * A snapshot of the values for an entry.
  560.      */
  561.     public final class Snapshot implements Closeable {
  562.         private final String key;
  563.         private final long sequenceNumber;
  564.         private final InputStream[] ins;

  565.         private Snapshot(String key, long sequenceNumber, InputStream[] ins) {
  566.             this.key = key;
  567.             this.sequenceNumber = sequenceNumber;
  568.             this.ins = ins;
  569.         }

  570.         /**
  571.          * Returns an editor for this snapshot's entry, or null if either the
  572.          * entry has changed since this snapshot was created or if another edit
  573.          * is in progress.
  574.          */
  575.         public Editor edit() throws IOException {
  576.             return DiskLruCache.this.edit(key, sequenceNumber);
  577.         }

  578.         /**
  579.          * Returns the unbuffered stream with the value for {@code index}.
  580.          */
  581.         public InputStream getInputStream(int index) {
  582.             return ins[index];
  583.         }

  584.         /**
  585.          * Returns the string value for {@code index}.
  586.          */
  587.         public String getString(int index) throws IOException {
  588.             return inputStreamToString(getInputStream(index));
  589.         }

  590.         @Override public void close() {
  591.             for (InputStream in : ins) {
  592.                 IoUtils.closeQuietly(in);
  593.             }
  594.         }
  595.     }

  596.     /**
  597.      * Edits the values for an entry.
  598.      */
  599.     public final class Editor {
  600.         private final Entry entry;
  601.         private boolean hasErrors;

  602.         private Editor(Entry entry) {
  603.             this.entry = entry;
  604.         }

  605.         /**
  606.          * Returns an unbuffered input stream to read the last committed value,
  607.          * or null if no value has been committed.
  608.          */
  609.         public InputStream newInputStream(int index) throws IOException {
  610.             synchronized (DiskLruCache.this) {
  611.                 if (entry.currentEditor != this) {
  612.                     throw new IllegalStateException();
  613.                 }
  614.                 if (!entry.readable) {
  615.                     return null;
  616.                 }
  617.                 return new FileInputStream(entry.getCleanFile(index));
  618.             }
  619.         }

  620.         /**
  621.          * Returns the last committed value as a string, or null if no value
  622.          * has been committed.
  623.          */
  624.         public String getString(int index) throws IOException {
  625.             InputStream in = newInputStream(index);
  626.             return in != null ? inputStreamToString(in) : null;
  627.         }

  628.         /**
  629.          * Returns a new unbuffered output stream to write the value at
  630.          * {@code index}. If the underlying output stream encounters errors
  631.          * when writing to the filesystem, this edit will be aborted when
  632.          * {@link #commit} is called. The returned output stream does not throw
  633.          * IOExceptions.
  634.          */
  635.         public OutputStream newOutputStream(int index) throws IOException {
  636.             synchronized (DiskLruCache.this) {
  637.                 if (entry.currentEditor != this) {
  638.                     throw new IllegalStateException();
  639.                 }
  640.                 return new FaultHidingOutputStream(new FileOutputStream(entry.getDirtyFile(index)));
  641.             }
  642.         }

  643.         /**
  644.          * Sets the value at {@code index} to {@code value}.
  645.          */
  646.         public void set(int index, String value) throws IOException {
  647.             Writer writer = null;
  648.             try {
  649.                 writer = new OutputStreamWriter(newOutputStream(index), Charsets.UTF_8);
  650.                 writer.write(value);
  651.             } finally {
  652.                 IoUtils.closeQuietly(writer);
  653.             }
  654.         }

  655.         /**
  656.          * Commits this edit so it is visible to readers.  This releases the
  657.          * edit lock so another edit may be started on the same key.
  658.          */
  659.         public void commit() throws IOException {
  660.             if (hasErrors) {
  661.                 completeEdit(this, false);
  662.                 remove(entry.key); // the previous entry is stale
  663.             } else {
  664.                 completeEdit(this, true);
  665.             }
  666.         }

  667.         /**
  668.          * Aborts this edit. This releases the edit lock so another edit may be
  669.          * started on the same key.
  670.          */
  671.         public void abort() throws IOException {
  672.             completeEdit(this, false);
  673.         }

  674.         private class FaultHidingOutputStream extends FilterOutputStream {
  675.             private FaultHidingOutputStream(OutputStream out) {
  676.                 super(out);
  677.             }

  678.             @Override public void write(int oneByte) {
  679.                 try {
  680.                     out.write(oneByte);
  681.                 } catch (IOException e) {
  682.                     hasErrors = true;
  683.                 }
  684.             }

  685.             @Override public void write(byte[] buffer, int offset, int length) {
  686.                 try {
  687.                     out.write(buffer, offset, length);
  688.                 } catch (IOException e) {
  689.                     hasErrors = true;
  690.                 }
  691.             }

  692.             @Override public void close() {
  693.                 try {
  694.                     out.close();
  695.                 } catch (IOException e) {
  696.                     hasErrors = true;
  697.                 }
  698.             }

  699.             @Override public void flush() {
  700.                 try {
  701.                     out.flush();
  702.                 } catch (IOException e) {
  703.                     hasErrors = true;
  704.                 }
  705.             }
  706.         }
  707.     }

  708.     private final class Entry {
  709.         private final String key;

  710.         /** Lengths of this entry's files. */
  711.         private final long[] lengths;

  712.         /** True if this entry has ever been published */
  713.         private boolean readable;

  714.         /** The ongoing edit or null if this entry is not being edited. */
  715.         private Editor currentEditor;

  716.         /** The sequence number of the most recently committed edit to this entry. */
  717.         private long sequenceNumber;

  718.         private Entry(String key) {
  719.             this.key = key;
  720.             this.lengths = new long[valueCount];
  721.         }

  722.         public String getLengths() throws IOException {
  723.             StringBuilder result = new StringBuilder();
  724.             for (long size : lengths) {
  725.                 result.append(' ').append(size);
  726.             }
  727.             return result.toString();
  728.         }

  729.         /**
  730.          * Set lengths using decimal numbers like "10123".
  731.          */
  732.         private void setLengths(String[] strings) throws IOException {
  733.             if (strings.length != valueCount) {
  734.                 throw invalidLengths(strings);
  735.             }

  736.             try {
  737.                 for (int i = 0; i < strings.length; i++) {
  738.                     lengths[i] = Long.parseLong(strings[i]);
  739.                 }
  740.             } catch (NumberFormatException e) {
  741.                 throw invalidLengths(strings);
  742.             }
  743.         }

  744.         private IOException invalidLengths(String[] strings) throws IOException {
  745.             throw new IOException("unexpected journal line: " + Arrays.toString(strings));
  746.         }

  747.         public File getCleanFile(int i) {
  748.             return new File(directory, key + "." + i);
  749.         }

  750.         public File getDirtyFile(int i) {
  751.             return new File(directory, key + "." + i + ".tmp");
  752.         }
  753.     }
  754. }
android经验分享.pdf 立即下载

相关推荐

两行代码实现android中分享

分享小demo,其实市面上这种代码很多, 按menu键出现分享菜单,通过intent 传递数据,实现分享。

Android 系统自带分享功能【图片、文字、CSV和PDF文件】

前言: 调用系统自带的分享功能将文本,当前界面截图、CSV和PDF文件分享出去; 效果图【测试机型:小米10】: 1、代码部分 ①:工具类:FileShareUtils public class FileShareUtils { private static final String TAG = "FileShareUtils"; //文件输出流 private static OutputStream outputStream; /** * 维度。A4尺寸为21

HelloWord的博客 3190

关于Android实现简单的微信朋友圈分享功能

主要介绍了关于Android实现简单的微信朋友圈分享功能,非常不错,具有参考借鉴价值,需要的的朋友参考下

Android开发-在应用之间共享文件

Android开发-在应用之间共享文件

m0_61787196的博客 1473

Android系统自带分享图片功能

简介 记录一个利用系统分享功能进行图片分享的工具类(代码是用Kotlin写的,都是比较简单的语法,部分可能需要自定义的地方都已经标出)。调用方式比较简单: Util.startShareImage(this) //this为当前的Activity实例 权限 记得添加文件操作权限, 另外需要注意6.0版本以上的权限管理 <uses android:name=android.permission.WRITE_EXTERNAL_STORAGE/> <uses-permission android:name=android.permission.READ_EXTERNA

改进差分进化算法及其求解柔性作业车间调度问题(Python代码实现)

内容概要:本文系统探讨了改进差分进化算法在求解柔性作业车间调度问题中的应用,并结合Python代码实现,展示了该算法相较于传统方法在全局搜索能力和收敛速度方面的优势。研究不仅聚焦于算法本身的改进策略,如变异、交叉和选择操作的优化,还深入分析了其在复杂制造环境中应对多目标、多约束调度问题的有效性。文中通过标准测试实例验证了算法性能,并与其他智能优化算法进行了对比分析,体现了其在实际工程应用中的潜力。此外,文档还关联了多无人机路径规划、电力系统状态估计、微电网优化、图像与信号处理等多个前沿技术领域,展现了智能优化算法在跨学科工程仿真与决策支持中的广泛适用性。; 适合人群:具备一定编程基础和工程背景,从事智能制造、自动化、工业工程、电气工程、控制科学与工程、计算机科学及相关领域的科研人员、高校研究生及企业研发技术人员。; 使用场景及目标:①为科研工作者提供可复现的智能优化算法代码框架,支持柔性作业车间调度、多无人机协同路径规划、电力系统优化等复杂工程问题的建模仿真;②辅助完成学术论文复现、课程设计、毕业设计或科研项目开发;③推动智能算法在生产调度、能源管理、交通规划等实际场景中的落地应用。; 阅读建议:建议读者结合文中提供的算法原理与代码实现,动手调试并验证不同参数设置对优化结果的影响,同时可参考荔枝科研社提供的完整资源包进行扩展学习与实践,以加深对算法机制与工程应用的理解。

Android中的缓存策略:LruCache和DiskLruCache

本篇文章主要是介绍Android中内置的两个缓存类的原理。所谓缓存,就是将获取的数据保存下来以便下次继续使用,这种技术尤其在网络请求和图片加载中有用,可以显著地提升App的性能表现。Android中也内置了两个缓存类,分别是和。

Tai_Monster的博客 1495

复现基于改进秃鹰算法的微电网群经济优化调度研究(Matlab代码实现)

内容概要:本文聚焦于“基于改进秃鹰算法的微电网群经济优化调度”研究,提出一种改进的秃鹰优化算法(IBOA)以解决传统智能优化算法在求解过程中易陷入局部最优、收敛速度慢等问题。通过引入自适应权重、动态搜索机制及种群多样性保持策略,显著增强了算法的全局搜索能力和收敛精度。研究构建了包含光伏发电、风力发电、储能系统、可控负荷及电网交互的微电网群多主体协同调度模型,以系统综合运行成本最小化为目标函数,综合考虑功率平衡、设备出力能力、储能荷电状态、爬坡速率等多种实际约束条件。利用Matlab平台进行仿真验证,并与标准BOA、PSO、GA等经典智能算法进行对比,结果表明所提算法在降低系统运行成本、提高可再生能源消纳率及优化调度效率方面具有明显优势。; 适合人群:适用于具备电力系统基础、优化理论知识及Matlab编程能力的高校研究生、科研人员及从事微电网、综合能源系统优化调度相关工作的工程技术人员。; 使用场景及目标:①用于微电网群或多微网系统的经济调度建模与仿真;②开展新型智能优化算法的设计、改进与性能评估;③支撑含高比例可再生能源的配电系统优化运行决策; 阅读建议:建议结合提供的Matlab代码深入理解算法实现细节与调度模型构建过程,重点分析改进策略对优化性能的影响,并可通过替换场景参数或引入其他算法进行横向对比实验,进一步掌握智能优化在能源系统中的应用方法。【复现】基于改进秃鹰算法的微电网群经济优化调度研究(Matlab代码实现)

UniversalImageLoader源码解析之 DiskCache

转载请注明出处:http://blog.csdn.net/crazy1235/article/details/70472306 FileNameGenerator DiskCache tryLoadBitmap UnlimitedDiskCache BaseDiskCache LimitedAgeDiskCache LruDiskCache get save remove clear上上一篇介绍了

crazy_jack 2389

DANN实战:用Python手把手教你实现对抗迁移学习(附完整代码)

本文通过Python实战教程,手把手教你实现DANN对抗迁移学习模型,以解决领域偏移问题。文章详细解析了领域对抗神经网络的核心机制,包括梯度反转层和领域判别器的构建,并提供了从数据准备、模型搭建到训练评估的完整代码,帮助开发者快速掌握这一强大的无监督领域自适应技术。

net55的博客 317

告别Root!用Termux+ADB在Android上玩转自动化(保姆级教程)

本文详细介绍了如何在非Root环境下使用Termux和ADB实现Android自动化操作,无需Root权限即可运行自动化脚本。通过Termux搭建Linux终端环境,结合ADB无线调试和Python脚本,实现点击、滑动、截图等自动化功能,适用于定时任务、自动签到等场景。

weixin_42548888的博客 536

Universal-Image-Loader源码收获

不熟悉Universal-Image-Loader使用的同学,可参考: “Universal-Image-Loader使用” http://xiaxveliang.blog.163.com/blog/static/29708034201582853043103/ Universal-Image-Loader 如今使用广泛,最近也将公司项目中的图片下载引擎替换为了Universal-Imag...

bjxiaxueliang的CODING小栈 758

SAP S/4HANA 可扩展性 – 面向初学者的简化指南

可扩展性(Extensibility)是 SAP ECC 和 SAP S/4HANA 的一项关键功能。它使客户能够通过定制其业务流程来创造竞争优势,并使合作伙伴能够通过量身定制的解决方案来丰富核心 ECC 或 S/4HANA。在过去的几十年中,SAP 的 on-premise 版本客户和合作伙伴主要使用经典的 ABAP 扩展性来扩展他们的 ERP 解决方案。经典扩展性允许 ABAP 开发人员使用甚至修改所有 SAP 对象。尽管经典扩展性非常强大和灵活,但在当今的云世界中,它已不再是一个好的选择。

SAP学习成长之路的博客 1809

xUtils源码阅读(8)-ImageDecoder

图片解析工具类,就是从文件读取图片内容,并处理成我们需要的样式(大小,旋转,修剪等)。 该工具类别看这么的长,实际上就一个函数,那就是decodeFileWithLock 所有其它的函数都是在为这个函数做服务呢,或者给这个函数做帮手呢。 这样再来看该类,就简单多了。 源码: /** * Created by wyouflf on 15/10/9. * ImageDecoder

wbzwind的专栏 1152

Windows下用MSYS2一键搞定Verilator安装(附国内镜像加速)

本文详细介绍了在Windows系统下,如何利用MSYS2工具和国内镜像源,快速、高效地完成Verilator的安装与配置。通过替换清华镜像源加速下载,并配合Pacman包管理器,实现近乎一键式的安装流程,有效解决了传统方法步骤繁琐、网络依赖下载慢的问题,为数字电路仿真提供了便捷的Windows环境解决方案。

weixin_29208327的博客 592

从SD更新字库到FLASH,再用LCD显示

用Flash当字库存储载体。思路是先将要用到的字库文件存在SD卡,然后存储到Flash,LCD显示时候从Flash中读取 还挺顺利的,移植的原子的程序,自己稍加修改,主要是我的液晶屏函数,Flash读写函数,还有存储文件的flash地址不一样。一晚上搞定,大小字体都OK。挺高兴哈哈。这几天忙工作事情有点耽搁了学习进展嘿嘿 在text.c的showstr函数中char的字体颜色随意设置的,可以显...

weixin_30505751的博客 914

Android的DiskLruCache硬盘缓存技术

之前记着LruCache我们从网络下载好的图片现存入到内存,下次直接从内存读取整体读取速度都变快了,但是我们退出应用下次再进来相同的图片是否可以不用从网络读取,所以DiskLruCache就是做这方面的工作。

左手木亽 818

SIMULINK开发项目实例 1000 例专栏之第960例--基于电力系统稳定性的建模与仿真场景:-含分布式电源的配电网电压稳定性研究

间歇性与随机性:例如,太阳能依赖于日照强度,风能依赖于风速,这使得它们的输出功率具有不确定性。逆变器接口:大多数分布式电源通过逆变器接入电网,这对电网的动态响应特性产生了影响。位置分散:通常分布在用户侧或靠近负荷中心的位置。本文详细介绍了如何使用Simulink结合Simscape Electrical 构建一个用于研究含分布式电源配电网电压稳定性的模型,并提供了详细的仿真流程说明。

xiaoheshang_123的博客 153

android分享各种文件

1.分享PDF文件: Intent intent = new Intent("android.intent.action.VIEW"); intent.addCategory("android.intent.category.DEFAULT"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Uri uri = Uri.

xuwenneng的博客 2457

eNSP中玩转Python自动化——解锁网工新姿势(一)

Python自动化一、安装Paramiko模块二、搭建实验环境1、桥接电脑网卡2、配置交换机IP地址交换机配置测试ensp的交换机与电脑的连通性:交换机配置SSHXshell验证三、Python脚本1、执行python脚本2、同步成功 一、安装Paramiko模块 首先安装Python3 然后安装pip解释器 最后安装Paramiko模块 Windows+R打开Cmd,输入命令: pip3 install paramiko 进入python,导入 paramiko模块: import paramiko

LiBai'S BLOG 2万+

Python爬虫实战:使用最新技术爬取新浪新闻首页数据

本文详细介绍了三种爬取新浪新闻首页的技术方案,从简单的requests-html到强大的Playwright,再到分布式Scrapy架构。小规模爬取:requests-html或aiohttp方案需要JavaScript渲染:Playwright方案大规模分布式爬取:Scrapy-Redis方案。

2201_76125261的博客 1243

Android 7.0适配 打开文件和分享文件

嗯,我就闲来无事想说一句,我是可爱的分割线(●’◡’●)。7.0的禁止不安全路径被外部访问。其中典型例子就是拍照。所以我以为分享图片也是需要适配,实验得知并不是。分享走的是系统的,所以不会有错误,如果你是打开文件的话,那么久需要适配content URL了。可是6.xx之后要动态申请权限,所以如果是对文件会发生读写操作的话需要把,申请读写权限意图说明。也就是 addFlags。1.Intent.FL

u011216273的博客 1万+

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

android 展示pdf文件

注:此方式展示pdf文件会增加apk大小3-4m左右 建议使用x5的webview进行加载pdf文件(可扩展)X5内核初始化下载失败的解决方案有道云笔记 2. 简单介绍 此篇文章主要还是将pdf文件进行下载到本sd目录下,之后转为file文件,交给pdfview进行展示,具体的展示pdf文件可进入pdfview源码中进行查看https://github.com/barteksc/AndroidPdfViewer 3.1 okhttp依赖:

72的博客 2355

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

android APP内显示PDF文件

android APP内显示PDF文件最近公司要做一个小功能,显示在APP内部显示pdf文件,刚接到任务感觉非常简单的一小功能,做的时候才发现在真的很不好实现。 因为android的webView与iOS的UIWebView不一样,不能够直接支持在线观看pdf文件,虽然谷歌官方给了个“http//docs.google.com/gviewembedded=true&url=”这样的解决方案,但是需要

u013605159的博客 1万+

android 在线预览pdf文件(目前最全)

android原生webView不支持预览pdf文件,ios却可以,所以android想要实现在线预览webView要通过其他方法,有以下几种方法: 一.andorid原生自带的pdf管理库,主要提供两个类pdfRender和pdfDocument,有兴趣的可以自己去了解一下,缺点就是必须是API>=21(也就是5.0以上)的版本才能支持,局限性太大。 二.一个github上面的开源库P...

怎么可以吃恐龙呢 3万+

AndroidPdf框架一览(一)

Android端PDF框架一览(一)1. 简介(1)android-pdfview第一个当然是github上面star 最多android-pdfview,它是基于谷歌的一款开源PDF浏览框架VuDroid的Android端开发框架, 支持缩略图,缩放,页面枚举,默认起始页。还有pdf加载监听,pdf页面滑动监听。 功能很强大,不过很可惜,功能有限,作者也在15年停止了维护。(2)pdfiump

xiaolongonly的博客 1万+
上一篇: Android提供的LruCache类简介
下一篇: Android 缓存Bitmaps
cding1818
博客等级 码龄17年 963粉丝 154原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值