三级缓存

1.简介

在Android中图片的使用必不可少的一部分,在考虑流量中,我们会涉及到图片的处理,这就有了我们现在的

的图片缓存


2.原理

图片的缓存,也就cache方法。这边使用的是 内存-文件-网络  这三层的cache机制,其中内存的缓存包含了

强引用缓存和软引用缓存,网路中加载不算是cache;我们处理图片的时候,是先从内存中找,如果内存中没有

,再从缓存中查找,如果缓存中没有,再从网络中http请求中获取到图片。在键值对中,这个图片

图片缓存的key值就是图片,URL则是hash值,value就是bitmap。所以,只要一个URL被下载过

,其中的图片就会被缓存起来。


关于Java对象中的软引用(softreference),如果一个对象具有软引用,内存空间足够,GC就不会回收,

但如果内存不足,就会回收这些对象的内存。只要GC没有回收,该对象就可以被程序使用。软引用的使用

可以是实现内存敏感的高速缓存,使用软引用也可以防止内存泄漏,课增强代码的稳定性。


缓存图片的代码:


/* 
* 图片管理 
* 异步获取图片,直接调用loadImage()函数,该函数自己判断是从缓存还是网络加载 
* 同步获取图片,直接调用getBitmap()函数,该函数自己判断是从缓存还是网络加载 
* 仅从本地获取图片,调用getBitmapFromNative() 
* 仅从网络加载图片,调用getBitmapFromHttp() 

*/ 
public class ImageManager implements IManager 
{ 
private final static String TAG = "ImageManager"; 

private ImageMemoryCache imageMemoryCache; //内存缓存 

private ImageFileCache imageFileCache; //文件缓存 

//正在下载的image列表 
public static HashMap<String, Handler> ongoingTaskMap = new HashMap<String, Handler>(); 

//等待下载的image列表 
public static HashMap<String, Handler> waitingTaskMap = new HashMap<String, Handler>(); 

//同时下载图片的线程个数 
final static int MAX_DOWNLOAD_IMAGE_THREAD = 4; 

private final Handler downloadStatusHandler = new Handler(){ 
public void handleMessage(Message msg) 
{ 
startDownloadNext(); 

}; 

public ImageManager() 
{ 
imageMemoryCache = new ImageMemoryCache(); 
imageFileCache = new ImageFileCache(); 


/** 
* 获取图片,多线程的入口 
*/ 
public void loadBitmap(String url, Handler handler) 
{ 
//先从内存缓存中获取,取到直接加载 
Bitmap bitmap = getBitmapFromNative(url); 
if (bitmap != null) 
{ 
Logger.d(TAG, "loadBitmap:loaded from native"); 
Message msg = Message.obtain(); 
Bundle bundle = new Bundle(); 
bundle.putString("url", url); 
msg.obj = bitmap; 
msg.setData(bundle); 
handler.sendMessage(msg); 

else 
{ 
Logger.d(TAG, "loadBitmap:will load by network"); 
downloadBmpOnNewThread(url, handler); 


/** 
* 新起线程下载图片 
*/ 
private void downloadBmpOnNewThread(final String url, final Handler handler) 
{ 
Logger.d(TAG, "ongoingTaskMap'size=" + ongoingTaskMap.size()); 

if (ongoingTaskMap.size() >= MAX_DOWNLOAD_IMAGE_THREAD) 
{ 
synchronized (waitingTaskMap) 
{ 
waitingTaskMap.put(url, handler); 


else 
{ 
synchronized (ongoingTaskMap) 
{ 
ongoingTaskMap.put(url, handler); 

new Thread() 
{ 
public void run() 
{ 
Bitmap bmp = getBitmapFromHttp(url); 
// 不论下载是否成功,都从下载队列中移除,再由业务逻辑判断是否重新下载 
// 下载图片使用了httpClientRequest,本身已经带了重连机制 
synchronized (ongoingTaskMap) 
{ 
ongoingTaskMap.remove(url); 


if(downloadStatusHandler != null) 
{ 
downloadStatusHandler.sendEmptyMessage(0); 


Message msg = Message.obtain(); 
msg.obj = bmp; 
Bundle bundle = new Bundle(); 
bundle.putString("url", url); 
msg.setData(bundle); 

if(handler != null) 
{ 
handler.sendMessage(msg); 


}.start(); 


/** 
* 依次从内存,缓存文件,网络上加载单个bitmap,不考虑线程的问题 
*/ 
public Bitmap getBitmap(String url) 
{ 
// 从内存缓存中获取图片 
Bitmap bitmap = imageMemoryCache.getBitmapFromMemory(url); 
if (bitmap == null) 
{ 
// 文件缓存中获取 
bitmap = imageFileCache.getImageFromFile(url); 
if (bitmap != null) 
{ 
// 添加到内存缓存 
imageMemoryCache.addBitmapToMemory(url, bitmap); 

else 
{ 
// 从网络获取 
bitmap = getBitmapFromHttp(url); 


return bitmap; 


/** 
* 从内存或者缓存文件中获取bitmap 
*/ 
public Bitmap getBitmapFromNative(String url) 
{ 
Bitmap bitmap = null; 
bitmap = imageMemoryCache.getBitmapFromMemory(url); 

if(bitmap == null) 
{ 
bitmap = imageFileCache.getImageFromFile(url); 
if(bitmap != null) 
{ 
// 添加到内存缓存 
imageMemoryCache.addBitmapToMemory(url, bitmap); 


return bitmap; 


/** 
* 通过网络下载图片,与线程无关 
*/ 
public Bitmap getBitmapFromHttp(String url) 
{ 
Bitmap bmp = null; 

try 
{ 
byte[] tmpPicByte = getImageBytes(url); 

if (tmpPicByte != null) 
{ 
bmp = BitmapFactory.decodeByteArray(tmpPicByte, 0, 
tmpPicByte.length); 

tmpPicByte = null; 

catch(Exception e) 
{ 
e.printStackTrace(); 


if(bmp != null) 
{ 
// 添加到文件缓存 
imageFileCache.saveBitmapToFile(bmp, url); 
// 添加到内存缓存 
imageMemoryCache.addBitmapToMemory(url, bmp); 

return bmp; 


/** 
* 下载链接的图片资源 

* @param url 

* @return 图片 
*/ 
public byte[] getImageBytes(String url) 
{ 
byte[] pic = null; 
if (url != null && !"".equals(url)) 
{ 
Requester request = RequesterFactory.getRequester( 
Requester.REQUEST_REMOTE, RequesterFactory.IMPL_HC); 
// 执行请求 
MyResponse myResponse = null; 
MyRequest mMyRequest; 
mMyRequest = new MyRequest(); 
mMyRequest.setUrl(url); 
mMyRequest.addHeader(HttpHeader.REQ.ACCEPT_ENCODING, "identity"); 
InputStream is = null; 
ByteArrayOutputStream baos = null; 
try { 
myResponse = request.execute(mMyRequest); 
is = myResponse.getInputStream().getImpl(); 
baos = new ByteArrayOutputStream(); 
byte[] b = new byte[512]; 
int len = 0; 
while ((len = is.read(b)) != -1) 
{ 
baos.write(b, 0, len); 
baos.flush(); 

pic = baos.toByteArray(); 
Logger.d(TAG, "icon bytes.length=" + pic.length); 

catch (Exception e3) 
{ 
e3.printStackTrace(); 
try 
{ 
Logger.e(TAG, 
"download shortcut icon faild and responsecode=" 
+ myResponse.getStatusCode()); 

catch (Exception e4) 
{ 
e4.printStackTrace(); 


finally 
{ 
try 
{ 
if (is != null) 
{ 
is.close(); 
is = null; 


catch (Exception e2) 
{ 
e2.printStackTrace(); 

try 
{ 
if (baos != null) 
{ 
baos.close(); 
baos = null; 


catch (Exception e2) 
{ 
e2.printStackTrace(); 

try 
{ 
request.close(); 

catch (Exception e1) 
{ 
e1.printStackTrace(); 



return pic; 


/** 
* 取出等待队列第一个任务,开始下载 
*/ 
private void startDownloadNext() 
{ 
synchronized(waitingTaskMap) 
{ 
Logger.d(TAG, "begin start next"); 
Iterator iter = waitingTaskMap.entrySet().iterator(); 

while (iter.hasNext()) 
{ 

Map.Entry entry = (Map.Entry) iter.next(); 
Logger.d(TAG, "WaitingTaskMap isn't null,url=" + (String)entry.getKey()); 

if(entry != null) 
{ 
waitingTaskMap.remove(entry.getKey()); 
downloadBmpOnNewThread((String)entry.getKey(), (Handler)entry.getValue()); 

break; 




public String startDownloadNext_ForUnitTest() 
{ 
String urlString = null; 
synchronized(waitingTaskMap) 
{ 
Logger.d(TAG, "begin start next"); 
Iterator iter = waitingTaskMap.entrySet().iterator(); 

while (iter.hasNext()) 
{ 
Map.Entry entry = (Map.Entry) iter.next(); 
urlString = (String)entry.getKey(); 
waitingTaskMap.remove(entry.getKey()); 
break; 


return urlString; 


/** 
* 图片变为圆角 
* @param bitmap:传入的bitmap 
* @param pixels:圆角的度数,值越大,圆角越大 
* @return bitmap:加入圆角的bitmap 
*/ 
public static Bitmap toRoundCorner(Bitmap bitmap, int pixels) 
{ 
if(bitmap == null) 
return null; 
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); 
Canvas canvas = new Canvas(output); 
final int color = 0xff424242; 
final Paint paint = new Paint(); 
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); 
final RectF rectF = new RectF(rect); 
final float roundPx = pixels; 
paint.setAntiAlias(true); 
canvas.drawARGB(0, 0, 0, 0); 
paint.setColor(color); 
canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 
canvas.drawBitmap(bitmap, rect, rect, paint); 
return output; 


public byte managerId() 
{ 
return IMAGE_ID; 

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值