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;
}
}
}