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