package in.srain.cube.file;
import android.content.Context;
import android.util.Log;
import in.srain.cube.cache.IFileCache;
import in.srain.cube.concurrent.SimpleExecutor;
import in.srain.cube.concurrent.SimpleTask;
import in.srain.cube.file.DiskLruCache.Editor;
import java.io.File;
import java.io.IOException;
public class LruFileCache implements IFileCache {
protected static final boolean DEBUG = true;
protected static final String TAG = "cube-file-cache";
private static final String DEFAULT_CACHE_DIR = "cube-cache";
private static final int DEFAULT_CACHE_SIZE = 1024 * 1024 * 10;
private static LruFileCache sDefault;
private static final int DISK_CACHE_INDEX = 0;
private DiskLruCache mDiskLruCache;
private final Object mDiskCacheLock = new Object();
private boolean mDiskCacheStarting = true;
private boolean mDiskCacheReady = false;
private File mDiskCacheDir;
private long mDiskCacheSize;
private boolean mIsDelayFlushing = false;
protected enum FileCacheTaskType {
init_cache, close_cache, flush_cache
}
public LruFileCache(Context context, String path, long size) {
mDiskCacheSize = size;
FileUtil.CacheDirInfo cacheDirInfo = FileUtil.getDiskCacheDir(context, path, size);
mDiskCacheDir = cacheDirInfo.path;
mDiskCacheSize = cacheDirInfo.realSize;
if (cacheDirInfo.isNotEnough) {
Log.e(TAG, String.format("no enough space for initDiskCache %s %s", cacheDirInfo.requireSize, cacheDirInfo.realSize));
}
}
public static LruFileCache getDefault(Context context) {
if (null == sDefault) {
sDefault = new LruFileCache(context, DEFAULT_CACHE_DIR, DEFAULT_CACHE_SIZE);
sDefault.initDiskCacheAsync();
}
return sDefault;
}
/**
* Initializes the disk cache. Note that this includes disk access so this should not be executed on the main/UI thread. By default an ImageProvider does not initialize the disk cache when it is created, instead you should call initDiskCache() to initialize it on a background thread.
*/
public void initDiskCache() {
if (DEBUG) {
Log.d(TAG, "initDiskCache " + this);
}
// Set up disk cache
synchronized (mDiskCacheLock) {
if (mDiskLruCache == null || mDiskLruCache.isClosed()) {
if (mDiskCacheDir != null) {
if (!mDiskCacheDir.exists()) {
mDiskCacheDir.mkdirs();
}
try {
mDiskLruCache = DiskLruCache.open(mDiskCacheDir, 1, 1, mDiskCacheSize);
if (DEBUG) {
Log.d(TAG, "Disk cache initialized " + this);
}
} catch (final IOException e) {
Log.e(TAG, "initDiskCache - " + e);
}
}
}
mDiskCacheStarting = false;
mDiskCacheReady = true;
mDiskCacheLock.notifyAll();
}
}
public void write(String key, String str) {
if (key == null) {
return;
}
synchronized (mDiskCacheLock) {
if (mDiskLruCache != null) {
try {
final Editor editor = mDiskLruCache.edit(key);
if (editor != null) {
editor.set(DISK_CACHE_INDEX, str);
editor.commit();
}
} catch (final IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public String read(String fileCacheKey) {
if (!mDiskCacheReady) {
initDiskCache();
}
synchronized (mDiskCacheLock) {
while (mDiskCacheStarting) {
try {
if (DEBUG) {
Log.d(TAG, "read wait " + this);
}
mDiskCacheLock.wait();
} catch (InterruptedException e) {
}
}
if (mDiskLruCache != null) {
DiskLruCache.Snapshot snapshot = null;
try {
snapshot = mDiskLruCache.get(fileCacheKey);
} catch (final IOException e) {
e.printStackTrace();
}
if (snapshot == null) {
return null;
}
String str = null;
try {
str = snapshot.getString(DISK_CACHE_INDEX);
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
return null;
}
}
public boolean has(String key) {
synchronized (mDiskCacheLock) {
while (mDiskCacheStarting) {
try {
if (DEBUG) {
Log.d(TAG, "check has wait " + this);
}
mDiskCacheLock.wait();
} catch (InterruptedException e) {
}
}
if (mDiskLruCache != null) {
try {
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
if (snapshot == null) {
return false;
}
return snapshot.has(DISK_CACHE_INDEX);
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}
public void delete(String key) {
synchronized (mDiskCacheLock) {
while (mDiskCacheStarting) {
try {
if (DEBUG) {
Log.d(TAG, "delete wait " + this);
}
mDiskCacheLock.wait();
} catch (InterruptedException e) {
}
}
try {
mDiskLruCache.remove(key);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public Editor open(String key) throws IOException {
if (null != mDiskLruCache) {
return mDiskLruCache.edit(key);
} else {
Log.e(TAG, "mDiskLruCache is null");
return null;
}
}
/**
* Clears both the memory and disk cache associated with this ImageProvider object. Note that this includes disk access so this should not be executed on the main/UI thread.
*/
public void clearCache() {
synchronized (mDiskCacheLock) {
mDiskCacheStarting = true;
mDiskCacheReady = false;
if (mDiskLruCache != null && !mDiskLruCache.isClosed()) {
try {
mDiskLruCache.delete();
if (DEBUG) {
Log.d(TAG, "Disk cache cleared");
}
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "clearCache - " + e);
}
mDiskLruCache = null;
initDiskCache();
}
}
}
/**
* Flushes the disk cache associated with this ImageProvider object. Note that this includes disk access so this should not be executed on the main/UI thread.
*/
public void flushDiskCache() {
synchronized (mDiskCacheLock) {
mIsDelayFlushing = false;
if (mDiskLruCache != null) {
try {
mDiskLruCache.flush();
if (DEBUG) {
Log.d(TAG, "Disk cache flushed");
}
} catch (IOException e) {
Log.e(TAG, "flush - " + e);
}
}
}
}
/**
* Closes the disk cache associated with this ImageProvider object. Note that this includes disk access so this should not be executed on the main/UI thread.
*/
public void closeDiskCache() {
synchronized (mDiskCacheLock) {
if (mDiskLruCache != null) {
try {
if (!mDiskLruCache.isClosed()) {
mDiskLruCache.close();
mDiskLruCache = null;
if (DEBUG) {
Log.d(TAG, "Disk cache closed");
}
}
} catch (IOException e) {
Log.e(TAG, "close - " + e);
}
}
}
}
/**
* A helper class to encapsulate the operate into a Work which will be executed by the Worker.
*/
private class FileCacheTask extends SimpleTask {
private FileCacheTask(FileCacheTaskType taskType) {
mTaskType = taskType;
}
private FileCacheTaskType mTaskType;
@Override
public void doInBackground() {
switch (mTaskType) {
case init_cache:
initDiskCache();
break;
case close_cache:
closeDiskCache();
break;
case flush_cache:
flushDiskCache();
break;
default:
break;
}
}
@Override
public void onFinish() {
}
void execute() {
SimpleExecutor.getInstance().execute(this);
}
void execute(int delay) {
SimpleTask.postDelay(new Runnable() {
@Override
public void run() {
execute();
}
}, delay);
}
}
/**
* initiate the disk cache
*/
public void initDiskCacheAsync() {
if (DEBUG) {
Log.d(TAG, "initDiskCacheAsync " + this);
}
new FileCacheTask(FileCacheTaskType.init_cache).execute();
}
/**
* close the disk cache
*/
public void closeDiskCacheAsync() {
if (DEBUG) {
Log.d(TAG, "closeDiskCacheAsync");
}
new FileCacheTask(FileCacheTaskType.close_cache).execute();
}
/**
* flush the data to disk cache
*/
public void flushDiskCacheAsync() {
if (DEBUG) {
Log.d(TAG, "flushDishCacheAsync");
}
new FileCacheTask(FileCacheTaskType.flush_cache).execute();
}
/**
* flush the data to disk cache
*/
public void flushDiskCacheAsyncWithDelay(int delay) {
if (DEBUG) {
Log.d(TAG, "flushDishCacheAsync");
}
if (mIsDelayFlushing) {
return;
}
mIsDelayFlushing = true;
new FileCacheTask(FileCacheTaskType.flush_cache).execute(delay);
}
@Override
public String getCachePath() {
return mDiskCacheDir.getPath();
}
@Override
public long getUsedSpace() {
if (null == mDiskLruCache) {
return 0;
}
return mDiskLruCache.size();
}
@Override
public long getMaxSize() {
return mDiskCacheSize;
}
}