Here is the complete implementation of DiskLruCache
.
First download DiskLruCache.java from AOSP.
Here is my DiskCache.java
a helper class for basic cache operations.
/**
* Created by Babar on 12-Aug-15.
*/
public class DiskCache
{
private Context context;
private static DiskCache diskCache;
public DiskLruCache mDiskLruCache;
private final Object mDiskCacheLock = new Object();
private BitmapProcessor bitmapProcessor;
private static final int DISK_CACHE_INDEX = 0;
public static boolean mDiskCacheStarting = true;
private static final String DISK_CACHE_SUBDIR = "ooredoo_thumbnails";
private static final int DISK_CACHE_SIZE = 1024 * 1024 * 100; // 100MB
public static DiskCache getInstance()
{
if(diskCache == null)
{
diskCache = new DiskCache();
}
return diskCache;
}
private DiskCache() {}
public void requestInit(Context context)
{
this.context = context;
bitmapProcessor = new BitmapProcessor();
new DiskCacheTask(this).execute(DiskCacheTask.INIT);
}
public void init() throws IOException {
synchronized (mDiskCacheLock)
{
if(mDiskLruCache == null || mDiskLruCache.isClosed())
{
File cacheDir = FileUtils.getDiskCacheDir(context, DISK_CACHE_SUBDIR);
if(!cacheDir.exists())
{
cacheDir.mkdir();
}
if(FileUtils.getUsableSpace(cacheDir) > DISK_CACHE_SIZE)
{
mDiskLruCache = DiskLruCache.open(cacheDir, 1, 1, DISK_CACHE_SIZE);
}
else
{
Logger.print("InitDiskCache failed: NOT enough space on disk");
}
}
mDiskCacheStarting = false; // Finished initialization
mDiskCacheLock.notifyAll(); // Wake any waiting threads
}
}
public void addBitmapToDiskCache(final String key, final Bitmap value) {
if (key == null || value == null) {
return;
}
synchronized (mDiskCacheLock)
{
if (mDiskLruCache != null) {
OutputStream out = null;
String encryptedKey = CryptoUtils.encryptToMD5(key);
Logger.print("addBitmapToDiskCache encryptToMD5: " + encryptedKey);
try {
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(encryptedKey);
if (snapshot == null) {
final DiskLruCache.Editor editor = mDiskLruCache.edit(encryptedKey);
if (editor != null) {
out = editor.newOutputStream(DISK_CACHE_INDEX);
value.compress(Bitmap.CompressFormat.JPEG, 100, out);
editor.commit();
out.close();
}
} else {
snapshot.getInputStream(DISK_CACHE_INDEX).close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
/**
* Get from disk cache.
*
* @param key Unique identifier for which item to get
* @return The bitmap if found in cache, null otherwise
*/
public Bitmap getBitmapFromDiskCache(final String key)
{
Bitmap bitmap = null;
String encryptedKey = CryptoUtils.encryptToMD5(key);
Logger.print("getBitmapFromDiskCache encryptToMD5: " + encryptedKey);
synchronized (mDiskCacheLock)
{
Logger.print("mDiskcachestarting: "+mDiskCacheStarting);
// Wait while disk cache is started from background thread
while (mDiskCacheStarting)
{
try
{
mDiskCacheLock.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
if(mDiskLruCache != null)
{
InputStream inputStream = null;
try
{
final DiskLruCache.Snapshot snapshot = mDiskLruCache.get(encryptedKey);
if(snapshot != null)
{
Logger.print("Disk cache hit");
inputStream = snapshot.getInputStream(DISK_CACHE_INDEX);
if(inputStream != null)
{
FileDescriptor fd = ((FileInputStream) inputStream).getFD();
// Decode bitmap, but we don't want to sample so give
// MAX_VALUE as the target dimensions
bitmap = bitmapProcessor.decodeSampledBitmapFromDescriptor(fd);
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if(inputStream != null)
{
try
{
inputStream.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
Logger.print("dCache getBitmapFromDiskCache synchronized completed");
}
Logger.print("dCache getBitmapFromDiskCache returning Bitmap");
return bitmap;
}
public void requestFlush()
{
new DiskCacheTask(this).execute(DiskCacheTask.FLUSH);
}
/**
* Flushes the disk cache associated with this ImageCache object. Note that this includes
* disk access so this should not be executed on the main/UI thread.
*/
public void flush()
{
synchronized (mDiskCacheLock)
{
if(mDiskLruCache != null)
{
try
{
mDiskLruCache.flush();
Logger.print("flush: disk cache flushed");
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
public void requestClose()
{
new DiskCacheTask(this).execute(DiskCacheTask.CLOSE);
}
/**
* Closes the disk cache associated with this ImageCache object. Note that this includes
* disk access so this should not be executed on the main/UI thread.
*/
public void close()
{
synchronized (mDiskCacheLock)
{
if(mDiskLruCache != null)
{
if(!mDiskLruCache.isClosed())
{
try
{
mDiskLruCache.close();
mDiskLruCache = null;
Logger.print("disk cache closed");
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}
/**
* Do not call this method unless you need to explicitly clear disk cache
*/
public void requestTearDown()
{
new DiskCacheTask(this).execute(DiskCacheTask.TEAR_DOWN);
}
public final void tearDown()
{
synchronized (mDiskCacheLock)
{
mDiskCacheStarting = true;
if(mDiskLruCache != null && !mDiskLruCache.isClosed())
{
try
{
mDiskLruCache.delete();
Logger.print("disk cache cleared");
}
catch (IOException e)
{
e.printStackTrace();
}
mDiskLruCache = null;
}
}
}
}
Here is BitmapProcesser.java
/**
* @author Babar
* @since 15-Jun-15.
*/
public class BitmapProcessor
{
public Bitmap decodeSampledBitmapFromStream(InputStream inputStream, URL url,
int reqWidth, int reqHeight) throws IOException {
Bitmap bitmap;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(inputStream, null, options);
int width = options.outWidth;
int height = options.outHeight;
Logger.print("@Req Width: "+reqWidth);
Logger.print("@Req Height: " + reqHeight);
Logger.print("@Actual Width: "+width);
Logger.print("@Actual Height: " + height);
int sampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
inputStream = url.openStream();
bitmap = BitmapFactory.decodeStream(inputStream, null, options);
if(bitmap != null)
{
width = bitmap.getWidth();
height = bitmap.getHeight();
Logger.print("@inSample:"+sampleSize);
Logger.print("@Modified Width: "+width);
Logger.print("@Modified Height: " + height);
}
return bitmap;
}
public Bitmap decodeSampledBitmapFromDescriptor(FileDescriptor fd)
{
/*final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(fd, null, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;*/
return BitmapFactory.decodeFileDescriptor(fd);
}
public Bitmap decodeSampledBitmapFromFile(String pathName, int reqWidth, int reqHeight) throws IOException {
Bitmap bitmap;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
int width = options.outWidth;
int height = options.outHeight;
Logger.print("@Req Width: "+reqWidth);
Logger.print("@Req Height: " + reqHeight);
Logger.print("@Actual Width: "+width);
Logger.print("@Actual Height: " + height);
int sampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
bitmap = BitmapFactory.decodeFile(pathName, options);
if(bitmap != null)
{
width = bitmap.getWidth();
height = bitmap.getHeight();
Logger.print("@inSample:"+sampleSize);
Logger.print("@Modified Width: "+width);
Lo
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…