/*
* Copyright (C) 2013 WhiteCat 白猫 (www.thinkandroid.cn)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ta.util.cache;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.ta.common.AndroidVersionCheckUtils;
import com.ta.util.TALogger;
import android.content.Context;
/**
* @Title TAFileCache
* @Package com.ta.util.cache
* @Description 文件的缓存操作类,包括内存缓存,与磁盘缓存
* @author 白猫
* @date 2013-1-20
* @version V1.0
*/
public class TAFileCache
{
// 默认内存储存储大小
private static final int DEFAULT_MEM_CACHE_SIZE = 1024 * 1024 * 5; // 5MB
// 默认磁盘存储大小
public static final int DEFAULT_DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
// 当压缩图片到磁盘的是默认格式
private static final int DEFAULT_COMPRESS_QUALITY = 70;
private static final int DISK_CACHE_INDEX = 0;
// 这些常量帮助轻松切换不同的缓存
private static final boolean DEFAULT_MEM_CACHE_ENABLED = true; // 默认内存缓存启用
private static final boolean DEFAULT_DISK_CACHE_ENABLED = true; // 默认磁盘缓存启用
private static final boolean DEFAULT_CLEAR_DISK_CACHE_ON_START = false;// 默认的清晰的磁盘缓存开始
private static final boolean DEFAULT_INIT_DISK_CACHE_ON_CREATE = false; // 默认的初始化的磁盘高速缓存开始
private TACacheParams mCacheParams;
private boolean mDiskCacheStarting = true;
private LruCache<String, byte[]> mMemoryCache;
private DiskLruCache mDiskLruCache;
private final Object mDiskCacheLock = new Object();
/**
* 创建一个新的TAFileCache对象使用指定的参数。
*
* @param cacheParams
* 缓存参数用来初始化缓存
*/
public TAFileCache(TACacheParams cacheParams)
{
init(cacheParams);
}
/**
* 创建一个缓存
*
* @param context
* 上下文信息
* @param uniqueName
* 这个标示名字会被添加到生成緩存文件夹
*
*/
public TAFileCache(Context context, String uniqueName)
{
init(new TACacheParams(context, uniqueName));
}
private void init(TACacheParams cacheParams)
{
mCacheParams = cacheParams;
if (mCacheParams.memoryCacheEnabled)
{
mMemoryCache = new LruCache<String, byte[]>(
mCacheParams.memCacheSize)
{
@Override
protected int sizeOf(String key, byte[] buffer)
{
return getSize(key, buffer);
}
};
}
// 如果默认的磁盘缓存没有初始化,那就需要初始化,在一个单独的线程由于磁盘访问。
if (!mCacheParams.initDiskCacheOnCreate)
{
// Set up disk cache
initDiskCache();
}
}
/**
* 初始化磁盘缓存
*/
public void initDiskCache()
{
// Set up disk cache
synchronized (mDiskCacheLock)
{
if (mDiskLruCache == null || mDiskLruCache.isClosed())
{
File diskCacheDir = mCacheParams.diskCacheDir;
if (mCacheParams.diskCacheEnabled && diskCacheDir != null)
{
if (!diskCacheDir.exists())
{
diskCacheDir.mkdirs();
}
long usableSpace = 0;
if (AndroidVersionCheckUtils.hasGingerbread())
{
usableSpace = TAExternalOverFroyoUtils
.getUsableSpace(diskCacheDir);
} else
{
usableSpace = TAExternalUnderFroyoUtils
.getUsableSpace(diskCacheDir);
}
if (usableSpace > mCacheParams.diskCacheSize)
{
try
{
mDiskLruCache = DiskLruCache.open(diskCacheDir, 1,
1, DEFAULT_DISK_CACHE_SIZE);
// mCacheParams.initDiskCacheOnCreate = true;
} catch (final IOException e)
{
mCacheParams.diskCacheDir = null;
TALogger.e(TAFileCache.this, "initDiskCache - " + e);
}
}
}
}
mDiskCacheStarting = false;
mDiskCacheLock.notifyAll();
}
}
/**
* 添加 byte[]类型数据到内存缓存和磁盘缓存
*
* @param data
* byte[]的惟一标识符来存储,一般是URL
* @param buffer
* 需要添加到缓存的数据
*/
public void addBufferToCache(String data, byte[] buffer)
{
if (data == null || buffer == null)
{
return;
}
// 添加到内存缓存
if (mMemoryCache != null && mMemoryCache.get(data) == null)
{
mMemoryCache.put(data, buffer);
}
synchronized (mDiskCacheLock)
{
// 添加到磁盘缓存
if (mDiskLruCache != null)
{
String key = "";
if (AndroidVersionCheckUtils.hasGingerbread())
{
key = TAExternalOverFroyoUtils.hashKeyForDisk(data);
} else
{
key = TAExternalUnderFroyoUtils.hashKeyForDisk(data);
}
OutputStream out = null;
try
{
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
if (snapshot == null)
{
final DiskLruCache.Editor editor = mDiskLruCache
.edit(key);
if (editor != null)
{
out = editor.newOutputStream(DISK_CACHE_INDEX);
out.write(buffer, 0, buffer.length);
editor.commit();
out.close();
}
} else
{
snapshot.getInputStream(DISK_CACHE_INDEX).close();
}
} catch (final IOException e)
{
TALogger.e(TAFileCache.this, "addBufferToCache - " + e);
} catch (Exception e)
{
TALogger.e(TAFileCache.this, "addBufferToCache - " + e);
} finally
{
try
{
if (out != null)
{
out.close();
}
} catch (IOException e)
{
}
}
}
}
}
/**
* 从内存缓存获取数据,如果内存缓存没有,它会从磁盘缓存获取填充到内存缓存
*
* @param data
* byte[]的惟一标识符来存储,一般是URL
* @return 返回byte[]类型的一个数据
*/
public byte[] getBufferFromMemCache(String data)
{
byte[] memValue = null;
try
{
if (mMemoryCache != null)
{
memValue = mMemoryCache.get(data);
}
/*
* if (memValue == null) { memValue =
* getInputStreamFromDiskCache(data); // 添加数据到内存缓存 if (memValue !=
* null && mMemoryCache != null && mMemoryCache.get(data) == null) {
* mMemoryCache.put(data, memValue); } }
*/
//
} catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
TALogger.e(TAFileCache.this, "获取缓存数据失败!");
}
return memValue;
}
/**
* 从磁盘缓存中获取数据
*
* @param data
* 独特的标识符项目得到
* @return 如果在缓存中找到相应的数据,则返回数据,否则为null
*/
public byte[] getBufferFromDiskCache(String data)
{
String key = "";
if (AndroidVersionCheckUtils.hasGingerbread())
{
key = TAExternalOverFroyoUtils.hashKeyForDisk(data);
} else
{
key = TAExternalUnderFroyoUtils.hashKeyForDisk(data);
}
synchronized (mDiskCacheLock)
{
while (mDiskCacheStarting)
{
try
{
mDiskCacheLock.wait();
} catch (InterruptedException e)
{
}
}
if (mDiskLruCache != null)
{
byte[] buffer = null;
try
{
final DiskLruCache.Snapshot snapshot = mDiskLruCache
.get(key);
if (snapshot != null)
{
InputStream fileInputStream = snapshot
.getInputStream(DISK_CACHE_INDEX);
buffer = readStream(fileInputStream);
// 添加数据到内存缓存
if (buffer != null && mMemoryCache != null
&& mMemoryCache.get(data) == null)
{
mMemoryCache.put(data, buffer);
}
return buffer;
}
} catch (final IOException e)
{
TALogger.e(TAFileCache.this, "getBufferFromDiskCache - "
+ e);
} catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
TALogger.e(TAFileCache.this, "getBufferFromDiskCache - "
+ e);
} finally
{
}
}
return null;
}
}
/*
* 得到图片字节流 数组大小
*/
public static byte[] readStream(InputStream inStream) throws Exception
{
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1)
{
outStream.write(buffer, 0, len);
}
outStream.close();
return outStream.toByteArray();
}
/**
* 位图的惟一标识符来存储清除内存和磁盘缓存都TAFileCache与此相关 对象。 注意,这包括对磁盘访问,所以这是不应当在主线程或
* UI线程上执行的。
*/
public void clearCache()
{
if (mMemoryCache != null)
{
mMemoryCache.evictAll();
}
synchronized (mDiskCacheLock)
{
mDiskCacheStarting = true;
if (mDiskLruCache != null && !mDiskLruCache.isClosed())
{
try
{
mDiskLruCache.delete();
} catch (IOException e)
{
TALogger.e(TAFileCache.this, "clearCache - " + e);
}
mDiskLruCache = null;
initDiskCache();
}
}
}
/**
* 磁盘缓存刷新TAFileCache与此相关的对象。注意,这包括对磁盘访问,所以这是不应当在主线程或 UI线程上执行的。
*/
public void flush()
{
synchronized (mDiskCacheLock)
{
if (mDiskLruCache != null)
{
try
{
mDiskLruCache.flush();
} catch (IOException e)
{
TALogger.e(TAFileCache.this, "flush - " + e);
}
}
}
}
/**
* 关闭磁盘缓存与此相关TAFileCache对象。注意,这包括对磁盘访问,所以这是不应当在主线程或 UI线程上执行的。
*/
public void close()
{
synchronized (mDiskCacheLock)
{
if (mDiskLruCache != null)
{
try
{
if (!mDiskLruCache.isClosed())
{
mDiskLruCache.close();
mDiskLruCache = null;
/*
* if (BuildConfig.DEBUG) { Log.d(TAG,
* "Disk cache closed"); }
*/
}
} catch (IOException e)
{
TALogger.e(TAFileCache.this, "close" + e);
}
}
}
}
/**
* 从获得byte[]的长度
*
* @param key
* @param value
* @return bytes类型的长度
*/
private int getSize(String key, byte[] value)
{
// TODO Auto-generated method stub
return value.length;
}
/**
* @Title TACacheParams
* @Package com.ta.util.cache
* @Description 缓存的参数类
* @author 白猫
* @date 2013-1-20
* @version V1.0
*/
public static class TACacheParams
{
public int memCacheSize = DEFAULT_MEM_CACHE_SIZE;
public int diskCacheSize = DEFAULT_DISK_CACHE_SIZE;
public File diskCacheDir;
public int compressQuality = DEFAULT_COMPRESS_QUALITY;
public boolean memoryCacheEnabled = DEFAULT_MEM_CACHE_ENABLED;
public boolean diskCacheEnabled = DEFAULT_DISK_CACHE_ENABLED;
public boolean clearDiskCacheOnStart = DEFAULT_CLEAR_DISK_CACHE_ON_START;
public boolean initDiskCacheOnCreate = DEFAULT_INIT_DISK_CACHE_ON_CREATE;
/**
* 初始化磁盘参数
*
* @param context
* 上下文
* @param uniqueName
* 缓存文件包名
*/
public TACacheParams(Context context, String uniqueName)
{
if (AndroidVersionCheckUtils.hasGingerbread())
{
diskCacheDir = TAExternalOverFroyoUtils.getDiskCacheDir(
context, uniqueName);
} else
{
diskCacheDir = TAExternalUnderFroyoUtils.getDiskCacheDir(
context, uniqueName);
}
}
/**
* 初始化磁盘参数
*
* @param diskCacheDir
* 缓存文件包
*/
public TACacheParams(File diskCacheDir)
{
this.diskCacheDir = diskCacheDir;
}
/**
* 设置缓存的大小
*
* @param context
* 上下文
* @param percent
* 设置分配缓存为本设备的百度比,以0.01f计算
*
*/
public void setMemCacheSizePercent(Context context, float percent)
{
if (percent < 0.05f || percent > 0.8f)
{
throw new IllegalArgumentException(
"setMemCacheSizePercent - percent must be "
+ "between 0.05 and 0.8 (inclusive)");
}
memCacheSize = Math.round(percent * getMemoryClass(context) * 1024
* 1024);
}
private static int getMemoryClass(Context context)
{
if (AndroidVersionCheckUtils.hasGingerbread())
{
return TAExternalOverFroyoUtils.getMemoryClass(context);
} else
{
return TAExternalUnderFroyoUtils.getMemoryClass(context);
}
}
}
}