package cn.koolcloud.ipos.appstore.cache;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import cn.koolcloud.ipos.appstore.cache.base.FileNameGenerator;
import cn.koolcloud.ipos.appstore.utils.Env;
import cn.koolcloud.ipos.appstore.utils.Logger;
/**
* image file cache in sdcard.
* this class includes the files in the sdcard, and writes bitmap to sdcard.
* @author Teddy
* @Create Date:2013-10-29
*/
public class ImageFileCache {
private static final String LOG_TAG = ImageFileCache.class.getSimpleName();
private static final String IMG_SUFFIX = ".cach";
private Context context;
private File cacheDir;
/** producer and consumer */
private BlockingQueue<UrlAndBitmap> bitmapWriteQueue;
private Thread writeThread = null;
private boolean createPathSuccess;
/**
* @param context
*/
public ImageFileCache(Context context) {
this.context = context;
initImageDir(context);
bitmapWriteQueue = new LinkedBlockingQueue<UrlAndBitmap>(); //FIFO, write bitmap to sdcard
writeThread = new Thread(writeRunnable);
writeThread.start();
}
private void initImageDir(Context context) {
cacheDir = Env.getImageCacheDirectory(context);
if(cacheDir != null) {
if(!cacheDir.exists()) {
if(cacheDir.mkdirs()) {//create all directory.
createPathSuccess = true;
} else {
createPathSuccess = false;
}
}
}
}
/**
* get image from
* @param url the url of image.
* @return Bitmap if a image existed in the sdcard,then return a bitmap.If didn't existed,return null.
*/
public Bitmap getImage(String url) {
File file = getFromFileCache(url);
if (file.exists()) {
Bitmap bmp;
try {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inPurgeable = true;
opt.inInputShareable = true;
FileInputStream fis = new FileInputStream(file);
bmp = BitmapFactory.decodeStream(fis, null, opt);
Logger.d(" getFromFileCache, " + bmp);
fis.close();
} catch (Exception e) {
bmp = null;
Logger.e("Memory heap size="+android.os.Debug.getNativeHeapAllocatedSize());
e.printStackTrace();
}
if(bmp == null) {
file.delete();
} else {
FileManager.updateFileTime(file);
Logger.d("get Bitmap From ImageFileCache, url=" + url);
return bmp;
}
}
return null;
}
/**
* consume.
* consume a task from bitmapWriteQueue.
* @param url hashcode
* @return the string of url encoded by hashcode
*/
private Runnable writeRunnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
UrlAndBitmap urlAndBitmap = bitmapWriteQueue.take();
if(!urlAndBitmap.bitmap.isRecycled())
saveImgToSD(urlAndBitmap.url, urlAndBitmap.bitmap);
}
} catch (InterruptedException e) {
Logger.d("the thread of writeRunnable is interrupted.");
}
}
};
/**
* produce.
* produce a task to bitmapWriteQueue.
* @param url hashcode
* @return the string of url encoded by hashcode
*/
public void addImgToSDTask(String url, Bitmap bitmap){
bitmapWriteQueue.add(new UrlAndBitmap(url, bitmap));
}
/**
* save image to sdcard.
* @param url hashcode
* @return the string of url encoded by hashcode
*/
public void saveImgToSD(String url, Bitmap bitmap){
if(bitmap == null || bitmap.isRecycled())
return;
if (FileManager.exsitSdcard()) {
if(cacheDir == null) {
initImageDir(context);
if(cacheDir == null) {
return ;
}
}
FileManager.reduceCache(cacheDir, FileManager.SD_SIZE_IN_MB,
FileManager.freeSpaceOnData(Environment.getExternalStorageDirectory().getPath()), FileManager.IMAGE_TIME_DIFF);//clear file cache
} else {
return ;
}
File file = getFromFileCache(url);
if(file.exists()){
file.delete();
}
try {
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
boolean isSaved = bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
if(isSaved) {
Logger.d("save image to sd successfully. url=" + url + ", filaName=" + file.getName());
} else {
Logger.d("failed to save image to sd. url=" + url + ", filaName=" + file.getName());
}
bos.close();
} catch (Exception e) {
Logger.w("failed to save image to sd. url=" + url + ", e=" + e);
}
}
/**
* get the file object from file cache.
*/
public File getFromFileCache(String url) {
//String fileName = urlToFileName(url);
String fileName = FileNameGenerator.generator(url);
File file = new File(cacheDir, fileName + IMG_SUFFIX);
return file;
}
/**
*
* @param url hashcode
* @return the string of url encoded by hashcode
*/
private String urlToFileName(String url) {
return String.valueOf(url.hashCode());
}
@SuppressWarnings("unused")
private void copyStream(InputStream is, OutputStream os){
final int buffer_size = 4096;
try
{
byte[] bytes=new byte[buffer_size];
for(;;)
{
int count=is.read(bytes, 0, buffer_size);
if(count==-1)
break;
os.write(bytes, 0, count);
}
}
catch(Exception ex){}
}
class UrlAndBitmap {
String url;
Bitmap bitmap;
public UrlAndBitmap(String url, Bitmap bitmap) {
this.url = url;
this.bitmap = bitmap;
}
}
public void deleteAll() {
if (FileManager.exsitSdcard()) {
if(cacheDir == null) {
initImageDir(context);
if(cacheDir == null) {
return ;
}
}
FileManager.deleteAll(cacheDir);//clear file cache
}
}
}