Android DiskLruCache parsing, hard disk cache

    Article reference: http://blog.csdn.net/guolin_blog/article/details/28863651 I would like
to thank the author for sharing and benefiting a lot! ! !

    As we all know, LruCache technology is the core solution to prevent multi-picture OOM, but LruCache only manages the storage and release of pictures in memory. If the picture is removed from memory, it needs to be reloaded from the network again. This is obviously Very time consuming. In this regard, Google provides a set of hard disk cache solutions: DiskLruCache (not officially written by Google, but officially certified).

1. Cache location:
    DiskLruCache does not limit the cache location of data and can be set freely, but usually most applications will choose the cache location as the path /sdcard/Android/data/<application package>/cache . There are two advantages to choosing this location: first, this is stored on the SD card, so even more data cached will not have any effect on the phone's built-in storage space, as long as the SD card space is sufficient. Second, this path is recognized by the Android system as the cache path of the application. When the program is uninstalled, the data here will also be cleared together, so that there will be no problem of a lot of residual data on the phone after the program is deleted. .

   In the bitmap folder under the path, there is a file named journal. The journal file is a log file of DiskLruCache. The operation records of the program for each picture are stored in this file. The program uses DiskLruCache technology. And a bunch of files with long file names in the bitmap are cached pictures.

2, the code uses:
    (1) First of all, you must know that DiskLruCache cannot create new instances. If we want to create an instance of DiskLruCache, we need to call its open() method. The interface is as follows:
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)

    The first parameter specifies the cache address of the data, the second parameter specifies the version number of the current application, the third parameter specifies how many cache files the same key can correspond to, basically 1 is passed, and the fourth parameter specifies The maximum number of bytes of data that can be cached.
    In order to prevent the situation where SD is just removed, we write a code to get the cache address:
   
public File getDiskCacheDir(Context context, String uniqueName) {
	String cachePath;
	if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
			|| !Environment.isExternalStorageRemovable()) {
		cachePath = context.getExternalCacheDir().getPath();
	} else {
		cachePath = context.getCacheDir().getPath();
	}
	return new File(cachePath + File.separator + uniqueName);
}

    When the SD card exists or the SD card cannot be removed, call the getExternalCacheDir() method to obtain the cache path, otherwise call the getCacheDir() method to obtain the cache path. The former gets the path /sdcard/Android/data/<application package>/cache, while the latter gets the path /data/data/<application package>/cache. uniqueName: cache folder name.
    Get the app version number:
public int getAppVersion(Context context) {
	try {
		PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
		return info.versionCode;
	} catch (NameNotFoundException e) {
		e.printStackTrace ();
	}
	return 1;
}

    Note: Whenever the version number changes, all data stored in the cache path will be cleared, because DiskLruCache believes that when the application has a version update, all data should be re-fetched from the Internet.
    so, open method:
DiskLruCache mDiskLruCache = null;
try {
	File cacheDir = getDiskCacheDir(context, "bitmap");
	if (!cacheDir.exists()) {
		cacheDir.mkdirs();
	}
	mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024);
} catch (IOException e) {
	e.printStackTrace ();
}

    First call the getDiskCacheDir() method to get the path to the cache address, and then judge whether the path exists, and create it if it does not exist. Then call the open() method of DiskLruCache to create an instance, and pass in the four parameters.
After having an instance of DiskLruCache, we can operate the cached data. The operation types mainly include writing, accessing, removing, etc.

    (2) The network URL image is written into the local cache:
    the writing operation is performed with the help of DiskLruCache.Editor This class is done. Similarly, this class cannot be new either, you need to call the edit() method of DiskLruCache to get the instance
public Editor edit(String key) throws IOException

    The key will be the file name of the cached file, and must be in one-to-one correspondence with the URL of the image, because the URL of the image may contain some special characters, which may be illegal when naming the file. In fact, the easiest way is to MD5 encode the URL of the picture. The encoded string must be unique and only contain characters such as 0-F, which fully conforms to the naming rules of the file.
   
public String hashKeyForDisk(String key) {
	String cacheKey;
	try {
		final MessageDigest mDigest = MessageDigest.getInstance("MD5");
		mDigest.update(key.getBytes());
		cacheKey = bytesToHexString(mDigest.digest());
	} catch (NoSuchAlgorithmException e) {
		cacheKey = String.valueOf(key.hashCode());
	}
	return cacheKey;
}

private String bytesToHexString(byte[] bytes) {
	StringBuilder sb = new StringBuilder();
	for (int i = 0; i < bytes.length; i++) {
		String hex = Integer.toHexString(0xFF & bytes[i]);
		if (hex.length() == 1) {
			sb.append('0');
		}
		sb.append(hex);
	}
	return sb.toString();
}

String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
String key = hashKeyForDisk(imageUrl);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);

    With an instance of DiskLruCache.Editor, we can call its newOutputStream() method to create an output stream, and then pass it into downloadUrlToStream() to download and write to the cache. Note that the newOutputStream() method receives an index parameter. Since 1 was specified when setting valueCount, the index can be passed as 0 here. After the write operation is completed, we also need to call the commit() method to commit to make the write take effect, and calling the abort() method means to abandon the write.
new Thread(new Runnable() {
	@Override
	public void run() {
		try {
			String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
			String key = hashKeyForDisk(imageUrl);
			DiskLruCache.Editor editor = mDiskLruCache.edit(key);
			if (editor != null) {
				OutputStream outputStream = editor.newOutputStream(0);
				if (downloadUrlToStream(imageUrl, outputStream)) {
					editor.commit();
				} else {
					editor.abort();
				}
			}
//This method does not have to be called for every write, but it is indispensable here
			mDiskLruCache.flush();
		} catch (IOException e) {
			e.printStackTrace ();
		}
	}
}).start();
private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
	HttpURLConnection urlConnection = null;
	BufferedOutputStream out = null;
	BufferedInputStream in = null;
	try {
		final URL url = new URL(urlString);
		urlConnection = (HttpURLConnection) url.openConnection();
		in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
		out = new BufferedOutputStream(outputStream, 8 * 1024);
		int b;
		while ((b = in.read()) != -1) {
			out.write(b);
		}
		return true;
	} catch (final IOException e) {
		e.printStackTrace ();
	} finally {
		if (urlConnection != null) {
			urlConnection.disconnect();
		}
		try {
			if (out != null) {
				out.close();
			}
			if (in != null) {
				in.close();
			}
		} catch (final IOException e) {
			e.printStackTrace ();
		}
	}
	return false;
}

   
    (3) Read cache:
   
public synchronized Snapshot get(String key) throws IOException

    The get() method requires a key to be passed in to get the corresponding cached data, and this key is undoubtedly the value after MD5 encoding the image URL.
    What is obtained here is a DiskLruCache.Snapshot object, and the input stream of the cached file can be obtained by calling its getInputStream() method. Similarly, the getInputStream() method also needs to pass an index parameter, and it is good to pass 0 here. A complete code to read the cache and load the image to the interface is as follows:
try {
	String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
	String key = hashKeyForDisk(imageUrl);
	DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
	if (snapShot != null) {
		InputStream is = snapShot.getInputStream(0);
		Bitmap bitmap = BitmapFactory.decodeStream(is);
		mImage.setImageBitmap (bitmap);
	}
} catch (IOException e) {
	e.printStackTrace ();
}


    (4) Remove the cache:
    
public synchronized boolean remove(String key) throws IOException

     Description: This method should not be called frequently. Because you don't need to worry about too much cached data taking up too much space on the SD card, DiskLruCache will automatically delete the excess cache according to the cache maximum value we set when calling the open() method. You should call the remove() method to remove the cache only when you are sure that the cache content corresponding to a key has expired and you need to get the latest data from the network.
    (5) Other APIs:
1. The size()
method will return the total number of bytes of all cached data in the current cache path, in bytes. If the application needs to display the total size of the current cached data on the interface, just It can be calculated by calling this method.
2. The flush()
method is used to synchronize the operation records in memory to the log file (that is, the journal file). This method is very important, because the premise that DiskLruCache can work properly depends on the content of the journal file. I called this method once when I explained the write cache operation, but in fact, it is not necessary to call the flush() method every time the cache is written. Frequent calls will not bring any benefits, only extra Increase the time to synchronize journal files. The standard approach is to call the flush() method once in the onPause() method of the Activity.
3. The close()
method is used to close the DiskLruCache, which is a method corresponding to the open() method. After it is closed, you can no longer call any method in DiskLruCache that manipulates the cached data. Usually, you should only call the close() method in the onDestroy() method of the Activity.
4. The delete( )
method is used to delete all cached data. For example, the function of manually cleaning the cache can be achieved by calling the delete() method of DiskLruCache.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326988741&siteId=291194637