Android open-source framework Universal-Image-Loader 6-hard disk cache policy
Zookeeper
Hard disk cache policy:
LimitedAgeDiscCache (sets the maximum time for a file to survive. When this value is exceeded, the file will be deleted)
UnlimitedDiscCache (this cache class has no restrictions)
Inheritance relationship:
public class LimitedAgeDiscCache extends BaseDiscCachepublic abstractclass BaseDiscCache implements DiskCachepublic interface DiskCache extends DiscCacheAwarepublic interface DiscCacheAware
Bottom-up parsing: 1. DiscCacheAware source code:
/** Interface for disk cache */@ Deprecatedpublic interface DiscCacheAware {/** return the root directory of the hard disk cache */File getDirectory (); /** return the cached image file * @ param imageUri Original image URI * @ return File of cached image or null-the image is not cached */File get (String imageUri ); /*** Save the image bitmap to the hard disk cache. * @ param imageUri Original image URI * @ param imageStream image input stream * @ param listener saves the process listener, which is not used in ImageLoader. core. listener. in the case of ImageLoadingProgressListener, you can ignore this listener * @ return true-saved successfully; false-failed to save. * @ throws IOException */boolean save (String imageUri, InputStream imageStream, IoUtils. copyListener listener) throws IOException;/*** (reload) saves the image bitmap to the hard disk cache. * @ param imageUri-Original image URI * @ param bitmap Image bitmap * @ return true-saved successfully; false-saved failed. * @ throws IOException */boolean save (String imageUri, Bitmap bitmap) throws IOException; /*** Delete the corresponding image file * @ param imageUri-image URI * @ return true-the image is deleted successfully; false-the specified URI image does not exist or the image file cannot be deleted */boolean remove (String imageUri);/** disable the hard disk cache and release resources. */void close ();/** clear hard disk cache */void clear ();}
I) the above Code uses IoUtils. CopyListener listener:
/** Listener and controller for copy process */public static interface CopyListener {/*** @ param current already loaded bytes * @ param total bytes to be loaded * @ return true-if the copying operation needs to continue, false-if the copying operation needs to be interrupted */boolean onBytesCopied (int current, int total );}
II) and ImageLoadingProgressListener:
/** Listener for image loading SS. */public interface ImageLoadingProgressListener {/*** is called when the loading process changes * @ param imageUri Image URI * @ param view image's View control, which can be null. * @ param current downloaded bytes size * @ param total bytes size */void onProgressUpdate (String imageUri, View view, intcurrent, inttotal );}
2. DiskCache source code: (the meaning is the same as that of MemoryCache in MemoryCacheAware. , But change the name)
/**Interface for disk cache*/public interface DiskCache extendsDiscCacheAware {}
3. BaseDiscCache source code:
/*** Base disk cache. */public abstract class BaseDiscCache implements DiskCache {/** {@ value */public static final int DEFAULT_BUFFER_SIZE = 32*1024; // 32 Kb public static final Bitmap. compressFormat DEFAULT_COMPRESS_FORMAT = Bitmap. compressFormat. PNG; public static final int DEFAULT_COMPRESS_QUALITY = 100; private static final String ERROR_ARG_NULL = "argument must be not null"; private st Atic final String TEMP_IMAGE_POSTFIX = ". tmp "; protected final File cacheDir; protected final File reserveCacheDir; protected final FileNameGenerator fileNameGenerator; protected int bufferSize = DEFAULT_BUFFER_SIZE; // 32 Kb protected Bitmap. compressFormat compressFormat = DEFAULT_COMPRESS_FORMAT; // Bitmap. compressFormat. PNG protected int compressQuality = DEFAULT_COMPRESS_QUALITY; // 100 public Base DiscCache (File cacheDir) {this (cacheDir, null);} public BaseDiscCache (File cacheDir, File reserveCacheDir) {this (cacheDir, reserveCacheDir, DefaultConfigurationFactory. createFileNameGenerator ();}/*** @ param cacheDir Directory for file caching * @ param reserveCacheDir can be null; Reserve directory for file caching. it's used when the primary directory isn't available. * @ param fileNameGenerator FileNameGenerator (Generates names for files at disk cache) for cached files */public BaseDiscCache (File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) {if (cacheDir = null) {throw new IllegalArgumentException ("cacheDir" + ERROR_ARG_NULL);} if (fileNameGenerator = null) {throw new partition ("fileNameGenerator" + ERROR_ARG_NULL);} this. cacheDir = cacheDi R; this. reserveCacheDir = reserveCacheDir; this. fileNameGenerator = fileNameGenerator;} @ Override/** rewrite DiscCacheAware. getDirectory () */public File getDirectory () {return cacheDir;} @ Override/** Override DiscCacheAware. get () */public File get (String imageUri) {return getFile (imageUri);} @ Override/** Save the image bitmap to the hard disk cache. for parameter meanings, see DisCacheAware */public boolean save (String imageUri, InputStream imageStre Am, IoUtils. copyListener listener) throws IOException {File imageFile = getFile (imageUri); // obtain the relevant File tmpFile = new File (imageFile. getAbsolutePath () + TEMP_IMAGE_POSTFIX); // It is defined. tmp file boolean loaded = false; // The loading Flag try {OutputStream OS = new BufferedOutputStream (new FileOutputStream (tmpFile), bufferSize); // bufferSize = 32 Kb try {loaded = IoUtils. copyStream (imageStream, OS, listener, BufferSize); // write the imageStream to the OS, see note III} finally {IoUtils. closeSilently (OS); // release resources. For more information, see note IV} finally {IoUtils. closeSilently (imageStream); if (loaded &&! TmpFile. renameTo (imageFile) {// see comment V loaded = false;} if (! Loaded) {tmpFile. delete (); // release resources upon failure} return loaded;} @ Override/** Save the image bitmap to the hard disk cache without IoUtils. copyListener */public boolean save (String imageUri, Bitmap bitmap) throws IOException {File imageFile = getFile (imageUri); File tmpFile = new File (imageFile. getAbsolutePath () + TEMP_IMAGE_POSTFIX); OutputStream OS = new BufferedOutputStream (new FileOutputStream (tmpFile), bufferSize); boolean s Tries = false; try {savedSuccessfully = bitmap. compress (compressFormat, compressQuality, OS); // Image Compression} finally {IoUtils. closeSilently (OS); if (savedSuccessfully &&! TmpFile. renameTo (imageFile) {savedSuccessfully = false;} if (! SavedSuccessfully) {tmpFile. delete () ;}} bitmap. recycle (); return savedSuccessfully;} @ Override public boolean remove (String imageUri) {return getFile (imageUri ). delete () ;}@ Override public void close () {// Nothing to do} @ Override public void clear () {File [] files = cacheDir. listFiles (); if (files! = Null) {for (File f: files) {f. delete () ;}}/ ** Returns file object (not null) for incoming image URI. file object can reference to non-existing file. */protected File getFile (String imageUri) {String fileName = fileNameGenerator. generate (imageUri); File dir = cacheDir; if (! CacheDir. exists ()&&! CacheDir. mkdirs () {if (reserveCacheDir! = Null & (reserveCacheDir. exists () | reserveCacheDir. mkdirs () {dir = reserveCacheDir;} return new File (dir, fileName); // Constructs a new file using the specified directory and name .} public void setBufferSize (intbufferSize) {this. bufferSize = bufferSize;} public void setCompressFormat (Bitmap. compressFormat compressFormat) {this. compressFormat = compressFormat;} public void setCompressQuality (intcompressQuality) {this. compressQuality = compressQuality ;}}
I) CompressFormat. PNG enumeration class used
/** Specifies the known formats a bitmap can be compressed into*/public enum CompressFormat { JPEG (0), PNG (1), WEBP (2); CompressFormat(int nativeInt) { this.nativeInt = nativeInt; } final int nativeInt;}
II) tool class: FileNameGenerator
/** Generates names for files at disk cache*/public interface FileNameGenerator { /** Generates unique file name for image defined by URI */ String generate(String imageUri);}
III) IoUtils. copyStream (imageStream, OS, listener, bufferSize );
/*** Copy stream, fires progress events by listener, can be interrupted by listener. ** @ param is Input stream * @ param OS Output stream * @ param listener can be null. Copy the Listener of the process and the Buffer Size of the copying controller * @ param bufferSize; it also indicates the "Step" of triggering the progress listener callback every time-that is, after each copied bufferSize bytes, the progress event * @ returntrue-stream is successfully copied; false-the copy operation is interrupted by listener * @ throws IOExcept Ion */public static boolean copyStream (InputStream is, OutputStream OS, CopyListener listener, int bufferSize) throws IOException {int current = 0; int total = is. available (); if (total <= 0) {total = DEFAULT_IMAGE_TOTAL_SIZE;} final byte [] bytes = new byte [bufferSize]; int count; if (shouldStopLoading (listener, current, total) return false; while (count = is. read (bytes, 0, bufferSize ))! =-1) {OS. write (bytes, 0, count); // write to the OS current + = count; // update the number of currently loaded bytes if (shouldStopLoading (listener, current, total )) return false;} OS. flush (); return true;} private static boolean shouldStopLoading (CopyListener listener, int current, int total) {if (listener! = Null) {boolean shouldContinue = listener. onBytesCopied (current, total); // participate in the above CopyListener if (! ShouldContinue) {if (100 * current/total <CONTINUE_LOADING_PERCENTAGE) {return true; // when loading exceeds 75%, load directly without interruption; otherwise, return true, generate interrupt }}return false ;}
IV) IoUtils. closeSilently () method
publicstaticvoid closeSilently(Closeable closeable) { try { closeable.close(); } catch (Exception e) { // Do nothing } }
The following is an analysis of Closeable in JDK:
For example, InputStream and OutputStream all implement the Closeable interface.
public abstract class InputStream extends Object implementsCloseablepublic abstract class OutputStream implements Closeable, Flushable
AutoCloseable source code:
Package java. lang;/*** defines an interface for classes that can be closed (or needed) once they are no longer in use * General Usage: * Closable foo = new Foo (); * try {*...; *} finally {* foo. close (); *} */public interface AutoCloseable {/** Close the corresponding Object and release all system resources it holds */void close () throws Exception ;}
Closeable source code:
Package java. io; public interface Closeable extends AutoCloseable {/*** different from AutoCloseable: although only the first call will have a valid effect, however, this close Method * is safe to be called multiple times on the same object. While AutoCloseable. close () can be called only once */void close () throws IOException ;}
V) File. renameTo () method
/*** Renames this file to {@ code newPath }. this Operation Supports files and directories * this operation has many methods that cause failures, including: * (1) Write permission (Write permission) write permission is required on the directories containing both the source and * destination paths. * (2) Search permission is required for all parents of both paths. */public boolean renameTo (File newPath) {try {Libcore. OS. rename (path, newPath. path); return true;} catch (ErrnoException errnoException) {return false ;}}
4. LimitedAgeDiscCache source code:
/*** Delete the file whose earliest loading time exceeds the specified time. the Cache size is unlimited. */public class LimitedAgeDiscCache extends BaseDiscCache {private final long maxFileAge; private final Map
LoadingDates = Collections. synchronizedMap (new HashMap
(); Public LimitedAgeDiscCache (File cacheDir, long maxAge) {this (cacheDir, null, DefaultConfigurationFactory. createFileNameGenerator (), maxAge);} public LimitedAgeDiscCache (File cacheDir, File reserveCacheDir, long maxAge) {this (cacheDir, reserveCacheDir, DefaultConfigurationFactory. createFileNameGenerator (), maxAge);}/*** @ param cacheDir Directory for file caching * @ param reserveCacheDir Is null; Reserve directory for file caching. it's used when the primary directory isn't available. * @ param fileNameGenerator Name generator for cached files * @ param maxAge Max file age (in seconds ). if file age will exceed this value then it'll be removed on next * treatment (and therefore be reloaded ). */public LimitedAgeDiscCache (File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGe Nerator, long maxAge) {// call public BaseDiscCache (File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) super (cacheDir, reserveCacheDir, fileNameGenerator); this. maxFileAge = maxAge * 1000; // convert to milliseconds} @ Override public File get (String imageUri) {File file = super. get (imageUri); if (file! = Null & file. exists () {boolean cached; Long loadingDate = loadingDates. get (file); // Map
LoadingDates if (loadingDate = null) {cached = false; loadingDate = file. lastModified ();} else {cached = true;} // Delete the policy if (System. currentTimeMillis ()-loadingDate> maxFileAge) {file. delete (); loadingDates. remove (file);} else if (! Cached) {loadingDates. put (file, loadingDate) ;}} return file ;}@ Override public boolean save (String imageUri, InputStream imageStream, IoUtils. copyListener listener) throws IOException {boolean saved = super. save (imageUri, imageStream, listener); rememberUsage (imageUri); // returns saved;} @ Override public boolean save (String imageUri, Bitmap bitmap) throws IOException {boolean saved = super. save (imageUri, bitmap); rememberUsage (imageUri); return saved ;}@ Override public boolean remove (String imageUri) {loadingDates. remove (getFile (imageUri); return super. remove (imageUri) ;}@ Override public void clear () {super. clear (); loadingDates. clear ();} private void rememberUsage (String imageUri) {File file = getFile (imageUri); long currentTime = System. currentTimeMillis (); file. setLastModified (currentTime); loadingDates. put (file, currentTime );}}
5. UnlimitedDiscCache source code:
/*** Default DiskCache implementation in the UIL framework. The Cache size is unlimited */public class UnlimitedDiscCache extends BaseDiscCache {public UnlimitedDiscCache (File cacheDir) {super (cacheDir );} public UnlimitedDiscCache (File cacheDir, File reserveCacheDir) {super (cacheDir, reserveCacheDir);}/*** @ param cacheDir Directory for file caching * @ param reserveCacheDir null-OK; reserve directory for file caching. it's used when the primary directory isn't available. * @ param fileNameGenerator {@ linkplain com. nostra13.universalimageloader. cache. disc. naming. fileNameGenerator * Name generator} for cached files */public UnlimitedDiscCache (File cacheDir, File delimiter, FileNameGenerator fileNameGenerator) {super (cacheDir, reserveCacheDir, fileNameGenerator );}}