Android-Universal-Image-Loader is an open-source project responsible for processing Image loading and caching. I read some source code in my spare time, which is a special record.
Consider the following factors for image file (Disk) caching:
1) definition of the cache file name
2) cache size
3) cached files: for example, files are saved for a limited time, the formats after image compression, and the compression ratio.
This project also supports modifying the file name when saving files in the disk cache: There are two ways to modify the file name when caching files, each method corresponds to a Java class
1) HashCodeFileNameGenerator, which obtains the hashcode of the file name and converts it to a string.
2) Md5FileNameGenerator, which encrypts the source file name with md5 and saves it. Both classes inherit the FileNameGenerator interface.
Shows the relationship between them.
<喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHAgYWxpZ249 "left"> A factory method createFileNameGenerator is provided in the DefaultConfigurationFactory class. This method returns a default FileNameGenerator object: HashCodeFileNameGenerator.
public static FileNameGenerator createFileNameGenerator() {return new HashCodeFileNameGenerator();}
The following describes the specific implementation of the disk cache:
The DiscCacheAware interface is defined first, which provides the following methods:
Method Name |
Description |
Return Value |
GetFileDectory () |
Back to the root directory of the disk cache |
File |
Get (String imageUri) |
Retrieve images from the cache based on the uri |
File |
Save (imageUri, InputStream iamgeStream, IoUtils. CopyListener listener) |
Save the image to the disk cache |
Boolean |
Save (imageUri, Bitmap bitmap) |
Save the bitMap object to the disk cache. |
Boolean |
Remove (imageUri) |
Delete an object based on imageUri |
Boolean |
Close () |
Disable disk cache and release resources |
Void |
Clear () |
Clear disk cache |
Void |
Then another interface DiskCache with no method is defined (this interface name should be named DiscCache better). This interface simply inherits the DiscCacheAware interface.
BaseDiscCache implements DiskCache. This class is an abstract class (one of the benefits of being defined as an abstract class is that you do not have to rewrite all the methods provided by the DiskCacheAware interface). This class defines the following (default) of the disk buffer) attribute:
1) The default cache size is 32 KB.
2) by default, the compressed image format is PNG (as the first parameter of the compress method of Bitmap)
3) by default, after compression, the image display quality is 100, that is, the compression ratio is 0, and no compression is performed (as the second parameter of compress)
Of course, this class also provides the set Method for modifying the compression image format and compression ratio and modifying the cache size. This class also encapsulates the following three attributes:
Protected final File cacheDir; // Save the cached File Directoryprotected final File cached; // backup cache diecloud. If cacheDir does not exist, use the protected backup cache protected final FileNameGenerator fileNameGenerator; // file name Generator
This class provides three Constructors
1) only one constructor initializes cacheDir and does not use the backup cache. It uses HashCodeFileNameGenerator to generate the object name of the target object.
2) Besides cacheDir and HashCodefileNameGenerator, the constructors of the two parameters can also initialize the backup cache.
3) The constructors of the three parameters must initialize cacheDir and filenNameGenerator; otherwise, an exception is reported.
The code for the three constructors is as follows:
public BaseDiscCache(File cacheDir) {this(cacheDir, null);}public BaseDiscCache(File cacheDir, File reserveCacheDir) {this(cacheDir, reserveCacheDir, DefaultConfigurationFactory.createFileNameGenerator());}public BaseDiscCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) {if (cacheDir == null) {throw new IllegalArgumentException("cacheDir" + ERROR_ARG_NULL);}if (fileNameGenerator == null) {throw new IllegalArgumentException("fileNameGenerator" + ERROR_ARG_NULL);}this.cacheDir = cacheDir;this.reserveCacheDir = reserveCacheDir;this.fileNameGenerator = fileNameGenerator;}
BasicDiscCache implements Six Methods except close. The following describes them one by one:
1) clear (): cyclically facilitates each File object in cacheDir. listFiles (), and then calls the delete () method of the File object to clear the cache.
2) getDirectory (): directly returns cacheDir
3) get (StringimageUri): This method calls an important method of BasicCahce getFile (String imageUri ).
This method is as follows (this method is also called in the save method)
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);}
4) Implementation of the save (StringimageUri, Bitmap bitmap) Method
Public boolean save (String imageUri, Bitmap bitmap) throws IOException {// get the File object of imageUri, this object encapsulates the cache path and the saved image name File imageFile = getFile (imageUri); // gets the tmpFile object File tmpFile = new File (imageFile. getAbsolutePath () + TEMP_IMAGE_POSTFIX); OutputStream OS = new BufferedOutputStream (new FileOutputStream (tmpFile), bufferSize); boolean bytes = false; try {// call compress to compress bitMap to saved in tempFile Successfully = bitmap. compress (compressFormat, compressQuality, OS);} finally {IoUtils. closeSilently (OS); // if the file saved successfully and tempFile is not successfully moved to imageFile, delete temFileif (savedSuccessfully &&! TmpFile. renameTo (imageFile) {savedSuccessfully = false;} if (! SavedSuccessfully) {tmpFile. delete () ;}// recycle bitmap. recycle (); return savedSuccessfully ;}
5) The logic for processing another save overload method is the same as that for processing, note that the two save methods are converted into a tempFile when the file is saved, and renameTo is called to rename the tempFile to imageFile.
BaseDiscCache has two extension classes. One is the UnlimitedDiscCache that does not limit the cache size and the LimitedAgeDiscCache that limits the cache time. UnlimitedDiscCache is simple, but it simply inherits BaseDiscCache and does not perform any extension on basediscc.
The LimitedAgeDiscCache class allows you to delete files that have been loaded for more than a specified time in the cache: delete files from the cache when the following conditions are met: Current System Time-Latest file modification time maxFileAge
This class provides two attributes:
1. maxFileAge (long type) sets the maximum loading time-out period. The modification time is initialized by the constructor. Once initialized, it cannot be changed (set the maximum file survival time. When this value is exceeded, delete the file)
2. loadingDates (Map ), This attribute is a map object, the key stores the image file to be cached, and the value stores the current time of the system by calling the save method, specifically, the data filled with loadingDates is implemented in the rememberUsage method below. This method is called in the two save methods of the class. First, the save method of the parent class is called, and then the method is called.
private void rememberUsage(String imageUri) {File file = getFile(imageUri);long currentTime = System.currentTimeMillis();file.setLastModified(currentTime);loadingDates.put(file, currentTime);}
The method for obtaining data from the cache is get (String imageUri). This class is used to override the BaseDiscDache method. This method obtains the latest update time loadingDate of the image represented by imageUri from loadingDates, the current time and loadingDate are used as the difference. If the difference is greater than maxFileAge, that is, the maximum loading time is checked, the file represented by the imageUri is deleted and the data in loadingDates is retrieved, of course, if map does not have imageUri, it will not involve timeout. In this case, the image will be placed in map. The specific implementation is as follows:
@Overridepublic File get(String imageUri) {File file = super.get(imageUri);if (file != null && file.exists()) {boolean cached;Long loadingDate = loadingDates.get(file);if (loadingDate == null) {cached = false;loadingDate = file.lastModified();} else {cached = true;}if (System.currentTimeMillis() - loadingDate > maxFileAge) {file.delete();loadingDates.remove(file);} else if (!cached) {loadingDates.put(file, loadingDate);}}return file;}