import
java.util.ArrayList;
import
java.util.HashMap;
import
java.util.LinkedList;
import
java.util.List;
import
android.graphics.Bitmap;
/**
* <p>Bitmap缓存池</p>
*
* <p>基于2Q改进算法缓存</p>
* <p>http://www.vldb.org/conf/1994/P439.PDF</p>
*
* 使用:
* LCache static lCache = new LCache();
*
* ...
*
*
* String imgUrl = "http://monstar.ch/uploads/img/201212/22085340_Zun9.jpg";
* if(lCache.isCached(imgUrl)){
* Bitmap tBitmap = lCache.get(imgUrl);
* }else{
* //从服务端获取图像
* Bitmap tBitmap = 服务端获取的Bitmap
*
* lCache.put(imgUrl,tBitmap);
* }
*
* @author lei.guoting
*/
public
class
LCache{
private
static
final
int
DEFAULT_MAX_SIZE = (
int
)(
1024
*
1024
*
3
.5f);
//默认缓存池大小 3.5M
private
static
final
int
DEFAULT_IN_QUEUE_MAX_SIZE =
40
;
//fInCacheQue队列默认大小
private
static
final
int
DEFAULT_OUT_QUEUE_MAX_SIZE =
60
;
//fOutCacheQue队列默认大小
private
static
final
int
DEFAULT_CACHE_QUEUE_MAX_SIZE =
0
;
//finalCacheQue队列默认大小
private
final
HashMap<String,Ref> cache;
//缓存池
private
final
Queue<String> fInCacheQue;
//一级缓存,Ain
private
final
Queue<String> fOutCacheQue;
//清楚一级缓存记录,Aout
private
final
Queue<String> finalCacheQue;
//最终缓存,Am
private
final
int
cacheMaxSize;
private
int
size;
private
int
curBitmapSize;
/**
* 构建默认大小的Cache
*/
public
LCache() {
this
(DEFAULT_MAX_SIZE);
}
/**
* 构建指定大小的Cache
*
* @param cacheMaxSize Cache最大容量
*/
public
LCache(
int
cacheMaxSize){
if
(
0
>= cacheMaxSize){
throw
new
IllegalArgumentException(
"cacheMaxSize must be greater than 0"
);
}
this
.cacheMaxSize = cacheMaxSize;
this
.cache =
new
HashMap<String,Ref>();
this
.fInCacheQue =
new
Queue<String>(DEFAULT_IN_QUEUE_MAX_SIZE);
this
.fOutCacheQue =
new
Queue<String>(DEFAULT_OUT_QUEUE_MAX_SIZE);
this
.finalCacheQue =
new
Queue<String>(DEFAULT_CACHE_QUEUE_MAX_SIZE);
}
/**
*
* @param key key值
* <a href="\"http://www.eoeandroid.com/home.php?mod=space&uid=7300\"" target="\"_blank\"">@return</a> true-key对应的Bitmap在该缓存池中
* false-key对应的Bitmap不在该缓存池中
*/
public
synchronized
boolean
isCached(String key){
return
this
.cache.containsKey(key);
}
/**
* 获取缓存池中Bitmap
*
* @param key key值
* @return Bitmap
*/
public
Bitmap get(String key){
if
(
null
== key){
throw
new
NullPointerException(
"The key can not be null"
);
}
if
(
""
.equals(key)){
throw
new
IllegalArgumentException(
"The key dons't value"
);
}
return
this
.getFromCache(key);
}
/**
* 将Bitmap缓存到该缓存池中
*
* @param key
* @param mBitmap
*/
public
synchronized
void
put(String key,Bitmap mBitmap){
if
(
this
.cache.containsKey(key)){
return
;
}
if
(
this
.fOutCacheQue.contains(key)){
this
.finalCacheQue.addToHead(key);
this
.fOutCacheQue.remove(key);
this
.reclaimCache(key,mBitmap);
}
else
{
this
.fInCacheQue.addToHead(key);
this
.reclaimCache(key,mBitmap);
if
(
this
.fInCacheQue.isOverflow()){
String tKey =
this
.fInCacheQue.removeFromTail();
this
.clearCache(tKey);
this
.fOutCacheQue.addToHead(tKey);
this
.fOutCacheQue.trim();
}
}
}
private
void
reclaimCache(String key, Bitmap mBitmap){
if
(
this
.hasFreeCache(mBitmap)){
this
.putIntoCache(key, mBitmap);
}
else
if
(
this
.fInCacheQue.isOverflow()){
do
{
String tKey =
this
.fInCacheQue.removeFromTail();
this
.clearCache(tKey);
this
.fOutCacheQue.addToHead(key);
}
while
(
this
.cacheMaxSize < (
this
.size +
this
.curBitmapSize));
this
.fOutCacheQue.trim();
this
.putIntoCache(key, mBitmap);
}
else
{
do
{
String tKey =
this
.finalCacheQue.removeFromTail();
this
.clearCache(tKey);
}
while
(
this
.cacheMaxSize < (
this
.size +
this
.curBitmapSize));
this
.putIntoCache(key, mBitmap);
}
}
private
void
putIntoCache(String key, Bitmap mBitmap){
this
.cache.put(key,
new
Ref(mBitmap,
this
.curBitmapSize));
this
.size +=
this
.curBitmapSize;
this
.curBitmapSize =
0
;
}
private
boolean
hasFreeCache(Bitmap mBitmap){
boolean
hasFreeCache =
true
;
this
.curBitmapSize =
this
.sizeOf(mBitmap);
if
(
this
.cacheMaxSize < (
this
.size +
this
.curBitmapSize)){
hasFreeCache =
false
;
}
return
hasFreeCache;
}
private
void
clearCache(String key){
Ref tRef =
this
.cache.remove(key);
if
(
null
!= tRef){
this
.size -= tRef.getSize();
if
(
null
!= tRef.getBitmap()){
tRef.getBitmap().recycle();
}
}
}
private
Bitmap getFromCache(String key){
Bitmap tBitmap =
null
;
synchronized
(
this
){
if
(
this
.finalCacheQue.contains(key)){
this
.finalCacheQue.moveToHead(key);
}
tBitmap =
this
.cache.get(key).getBitmap();
}
return
tBitmap;
}
/**
* Bitmap 存储大小
*
* @param mBitmap
* @return
*/
private
int
sizeOf (Bitmap mBitmap){
int
weight =
0
;
switch
(mBitmap.getConfig()){
case
ALPHA_8 :
weight =
1
;
break
;
case
ARGB_4444 :
weight =
2
;
break
;
case
ARGB_8888 :
weight =
4
;
break
;
case
RGB_565 :
weight =
2
;
break
;
default
:
weight =
1
;
break
;
}
return
(mBitmap.getWidth() * mBitmap.getHeight() * weight);
}
public
synchronized
void
destory(){
this
.cache.clear();
this
.finalCacheQue.clear();
this
.fInCacheQue.clear();
this
.fOutCacheQue.clear();
}
/**
* 队列
*/
class
Queue<T>{
private
int
capacity;
private
final
List<T> list;
/**
* @param capacity 队列最大容量,可为0;如果capacity为0,当前队列无大小限制
*/
public
Queue(
int
capacity){
this
.capacity = capacity;
if
(
0
<
this
.capacity){
this
.list =
new
ArrayList<T>(
this
.capacity);
}
else
{
this
.list =
new
LinkedList<T>();
}
}
/**
* 队列容量
*
* @return 队列容量
*/
public
int
capacity(){
return
this
.capacity;
}
/**
* 队列当前大小
*
* @return 队列大小
*/
public
int
size(){
return
this
.list.size();
}
/**
* 该队列中是否有key值
*
* @param key
* @return true 存在key值,false 不存在key值
*/
public
boolean
contains(T key){
return
this
.list.contains(key);
}
/**
* 队列是否溢出
*
* @return
*/
public
boolean
isOverflow(){
if
(
0
== capacity){
return
false
;
}
else
{
return
(
this
.list.size() >
this
.capacity);
}
}
/**
* 将队列中key移动到队列头
*
* @param key 值
*/
public
void
moveToHead(T key){
this
.list.remove(key);
this
.list.add(key);
}
/**
* 将key添加到队列头
*
* @param key 值
*/
public
void
addToHead(T key){
this
.list.add(key);
}
/**
* 删除队列最后一个值
*
* @return 当前删除队列值
*/
public
T removeFromTail(){
T tKey =
null
;
if
(
0
<
this
.list.size()){
tKey =
this
.list.remove(
0
);
}
return
tKey;
}
/**
* 删除队列中key值
*
* @param key key值
* @return 删除成功返回当前key,删除失败返回null
*/
public
T remove(T key){
if
(
this
.list.remove(key)){
return
key;
}
return
null
;
}
/**
* 将Queue中超过capacity的长度截取掉
* 如果list.size <= capacity, 什么都不做
*/
public
void
trim(){
if
((
0
== capacity) || (
this
.list.size() <=
this
.capacity)){
return
;
}
int
tNum =
this
.list.size() -
this
.capacity;
for
(
int
idx =
0
; idx < tNum; idx ++){
this
.removeFromTail();
}
}
public
void
clear(){
this
.list.clear();
}
}
class
Ref{
//private SoftReference<Bitmap> softReference;
private
Bitmap mBitmap;
private
int
size;
public
Ref(Bitmap mBitmap,
int
size){
//this.softReference = new SoftReference<Bitmap>(mBitmap);
this
.mBitmap = mBitmap;
this
.size = size;
}
public
int
getSize(){
return
size;
}
public
Bitmap getBitmap(){
//return softReference.get();
return
this
.mBitmap;
}
}
}