package net.dev123.yibo.service.cache;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import net.dev123.commons.util.StringUtil;
import net.dev123.yibo.YiBoApplication;
import net.dev123.yibo.common.Constants;
import net.dev123.yibo.common.ImageUtil;
import net.dev123.yibo.service.cache.wrap.CachedImage;
import net.dev123.yibo.service.cache.wrap.CachedImageKey;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.util.Log;
public class ImageCache implements MapCache<CachedImageKey, CachedImage> {
private static final String TAG = "ImageCache";
public static final String IMAGE_HEAD_MINI = "head_mini";
public static final String IMAGE_HEAD_NORMAL = "head_normal";
public static final String IMAGE_THUMBNAIL = "thumbnail";
public static final String IMAGE_MIDDLE = "middle";
public static final String IMAGE_ORIGIN = "origin";
public static final String IMAGE_TEMP = "temp";
public static final String IMAGE_EMOTIONS = "emotions";
public static final String[] IMAGE_FOLDER = {
IMAGE_HEAD_MINI, IMAGE_HEAD_NORMAL, IMAGE_THUMBNAIL,
IMAGE_MIDDLE, IMAGE_ORIGIN, IMAGE_TEMP, IMAGE_EMOTIONS
};
private static final long BIG_IMG_SIZE_LEVEL = 120 * 120 * 4;
private Map<CachedImageKey, CachedImage> memoryCache;
//private Map<String, BitmapWrap> localCache;
private static String filePath = "/sdcard/.yibo"; //赋值是为增加默认配置;
private static String secondaryFilePath = "/data/data/net.dev123.yibo/cache";
public ImageCache(String filePath, String secondFilePath) {
memoryCache = new HashMap<CachedImageKey, CachedImage>(60, 1.0f);
if (StringUtil.isNotBlank(filePath)) {
ImageCache.filePath = filePath;
}
if (StringUtil.isNotBlank(secondFilePath)) {
ImageCache.secondaryFilePath = secondFilePath;
}
File cacheFile = new File(ImageCache.filePath);
if (!cacheFile.exists()) {
cacheFile.mkdir();
}
for (String folder : IMAGE_FOLDER) {
File file = new File(ImageCache.filePath + File.separator + folder);
if (!file.exists()) {
file.mkdirs();
}
file = new File(ImageCache.secondaryFilePath + File.separator + folder);
if (!file.exists()) {
file.mkdirs();
}
}
getCacheHeap();
}
private void getCacheHeap() {
}
@Override
public void clear() {
flush();
memoryCache.clear();
}
@Override
public boolean containsKey(CachedImageKey key) {
boolean isContain = true;
if (!memoryCache.containsKey(key)) {
String filePath = getRealPath(key);
if (filePath == null) {
isContain = false;
}
}
return isContain;
}
@Override
public boolean reclaim(ReclaimLevel level) {
switch(level) {
case LIGHT:
Set<CachedImageKey> set = memoryCache.keySet();
Object[] infoArray = null;
try {
infoArray = (Object[])set.toArray();
} catch(Exception e) {}
if (infoArray == null) {
break;
}
int size = infoArray.length;
Object temp;
CachedImageKey key;
for (int i = 0; i < size; i++) {
temp = infoArray[i];
if (temp == null
|| !(temp instanceof CachedImageKey)) {
continue;
}
key = (CachedImageKey)temp;
CachedImage wrap = memoryCache.get(key);
if ( wrap == null
|| wrap.getWrap() == null) {
memoryCache.remove(key);
}
}
break;
case MODERATE:
case WEIGHT:
memoryCache.clear();
break;
}
return true;
}
@Override
public void flush() {
return;
}
@Override
public CachedImage get(CachedImageKey key) {
boolean isContain = containsKey(key);
if (!isContain) {
return null;
}
CachedImage bWrap = null;
if (memoryCache.containsKey(key)) {
bWrap = memoryCache.get(key);
}
if (bWrap != null && bWrap.getWrap() != null) {
if(Constants.DEBUG) Log.v("ImageCache", "hit memory cache");
return bWrap;
}
CachedImage temp = read(key);
Bitmap bitmap = null;
if (temp != null) {
bitmap = temp.getWrap();
if (bWrap != null) {
bWrap.setWrap(bitmap);
} else {
bWrap = temp;
memoryCache.put(key, bWrap);
}
if(Constants.DEBUG) Log.v("ImageCache", "hit local cache");
}
return bWrap;
}
@Override
public void put(CachedImageKey key, CachedImage value) {
if (value == null
|| key == null
|| StringUtil.isEmpty(key.getImageUrl())) {
return;
}
Bitmap bitmap = value.getWrap();
if (bitmap != null
&& !value.isLocalCached()) {
write(key, value);
value.setLocalCached(true);
}
memoryCache.put(key, value);
if (memoryCache.size() > 50) {
reclaim(ReclaimLevel.LIGHT);
}
}
@Override
public void remove(CachedImageKey key) {
memoryCache.remove(key);
}
@Override
public CachedImage read(CachedImageKey key) {
long startRead = System.currentTimeMillis();
String realPath = getRealPath(key);
if (realPath == null) {
return null;
}
File file = new File(realPath);
byte[] fileBytes = null;
InputStream fis = null;
try {
fis = new FileInputStream(file);
fis = new BufferedInputStream(fis, 8192);
int offset = 0;
int byteCount = (int)file.length();
int readCount = 0;
fileBytes = new byte[byteCount];
while((readCount = fis.read(fileBytes, offset, byteCount)) > 0) {
offset += readCount;
byteCount -= readCount;
}
} catch (FileNotFoundException e) {
if(Constants.DEBUG) e.printStackTrace();
} catch (IOException e) {
if(Constants.DEBUG) e.printStackTrace();
} catch (Exception e) {
if(Constants.DEBUG) e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BitmapFactory.Options options = new BitmapFactory.Options();
//先指定原始大小
options.inSampleSize = 1;
//只进行大小判断
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
BitmapFactory.decodeByteArray(fileBytes, 0, fileBytes.length, options);
long bitmapSize = ImageUtil.calculateBitmapSize(options);
if (bitmapSize >= BIG_IMG_SIZE_LEVEL) {
options.inSampleSize = ImageUtil.getScaleSampleSize(options, 120);
if(Constants.DEBUG) Log.d(TAG, "compress local big bitmap");
}
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeByteArray(fileBytes, 0, fileBytes.length, options);
CachedImage wrap = new CachedImage(bitmap);
long endRead = System.currentTimeMillis();
if (Constants.DEBUG) Log.d(TAG, "read local bitmap use time: " + (endRead - startRead) + "ms");
return wrap;
}
@Override
public void write(CachedImageKey key, CachedImage value) {
if (value == null) {
return;
}
Bitmap bitmap = value.getWrap();
if (bitmap == null) {
return;
}
String fileName = File.separator + IMAGE_FOLDER[key.getCacheType()] +
File.separator + key.getCachedName();
File file = new File(filePath + fileName);
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
file = new File(secondaryFilePath + fileName);
}
if (file.exists()) {
return;
}
if (Constants.DEBUG) Log.v(TAG, file.getPath() + "|media state: " + Environment.getExternalStorageState());
FileOutputStream fos = null;
try {
file.createNewFile();
fos = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//把数组写入文件
public static void write(CachedImageKey key, byte[] imgBytes) {
if (key == null ||
StringUtil.isEmpty(key.getImageUrl()) ||
imgBytes == null ||
imgBytes.length == 0
) {
return;
}
String fileName = File.separator + IMAGE_FOLDER[key.getCacheType()] +
File.separator + key.getCachedName();
File file = new File(filePath + fileName);
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
file = new File(secondaryFilePath + fileName);
}
if (file.exists()) {
return;
}
FileOutputStream fos = null;
try {
file.createNewFile();
fos = new FileOutputStream(file);
fos.write(imgBytes);
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static String getRealPath(CachedImageKey key) {
String filePath = null;
if (key == null || StringUtil.isEmpty(key.getImageUrl())) {
return filePath;
}
filePath = File.separator + IMAGE_FOLDER[key.getCacheType()] +
File.separator + key.getCachedName();
File file = new File(ImageCache.filePath + filePath);
if (file.exists() && file.isFile()) {
return file.getPath();
}
file = new File(ImageCache.secondaryFilePath + filePath);
if (file.exists() && file.isFile()) {
return file.getPath();
}
return null;
}
public static String getImageSavePath(CachedImageKey key) {
String filePath = null;
if (key == null || StringUtil.isEmpty(key.getImageUrl())) {
return null;
}
filePath = File.separator + IMAGE_FOLDER[key.getCacheType()] +
File.separator + key.getCachedName();
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
filePath = ImageCache.filePath + filePath;
} else {
filePath = ImageCache.secondaryFilePath + filePath;
}
return filePath;
}
public static String getTempFolder() {
String tempFolder = YiBoApplication.getSdcardCachePath() +
File.separator + IMAGE_TEMP;
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
tempFolder = YiBoApplication.getInnerCachePath() + File.separator + IMAGE_TEMP;
}
return tempFolder;
}
public static String getImageFolder(String imageType) {
String tempFolder = YiBoApplication.getSdcardCachePath() +
File.separator + imageType;
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
tempFolder = YiBoApplication.getInnerCachePath() + File.separator + imageType;
}
return tempFolder;
}
public void stat() {
int imageCount = 0;
int headCount = 0;
int thumbnailCount = 0;
int bigCount = 0;
int memorySize = 0;
for (CachedImageKey info : memoryCache.keySet()) {
CachedImage wrap = memoryCache.get(info);
imageCount++;
if (wrap == null) {
continue;
}
Bitmap bitmap = wrap.getWrap();
if (bitmap == null) {
continue;
}
if (info.getCacheType() == CachedImageKey.IMAGE_HEAD_MINI
|| info.getCacheType() == CachedImageKey.IMAGE_HEAD_NORMAL) {
headCount ++;
} else if (info.getCacheType() == CachedImageKey.IMAGE_THUMBNAIL) {
thumbnailCount++;
} else {
bigCount++;
}
memorySize += bitmap.getWidth() * bitmap.getHeight() * 4;
}
System.out.println("ImageCache stat->"
+ ", imageCount:" + imageCount
+ ", headCount:" + headCount
+ ", thumbnailCount:" + thumbnailCount
+ ", bigCount:" + bigCount
+ ", memorySize:" + memorySize);
}
}