android异步图片加载三之handler+线程池+消息队列模式+缓存
假象现在有这样一个需求:
一个微博客户端或者多媒体客户端需要从服务端拉取一些数据,该数据中包含了很多图片,如果不用异步加载方式,可能会使主线程阻塞导致ANR异常,但是异步加载后如果每次都通过网络去下载图片,性能上会差很多,而且也会浪费流量,导致用户的不满,故现在增加一个缓存用来存储图片,缓存中包含内存存储和sdcard存储。先从缓存中去,在缓存中先从内存中取出,如果内存中没有再从sdcard去,如果sdcard中存在则直接返回该图片资源并放入内存中,如果两者都没有则从网络上下载,下载后并放入sdcard中供下次使用,这样就节约了资源开销,下面是主要代码:
PicManager(用来处理图片的操作):
publicclassPicManager {
privateMap> imgCache ;
privateContext ctx;
publicPicManager(Map> imgCache,Context ctx) {
this.ctx = ctx;
this.imgCache = imgCache;
}
/**
* 从网络上下载
* @param url
* @return
*/
publicBitmap getBitMapFromUrl(String url) {
Bitmap bitmap = null;
URL u =null;
HttpURLConnection conn = null;
InputStream is = null;
try{
u = newURL(url);
conn = (HttpURLConnection)u.openConnection();
is = conn.getInputStream();
bitmap = BitmapFactory.decodeStream(is);
} catch(Exception e) {
e.printStackTrace();
}
returnbitmap;
}
/**
* 从文件中读取
* @return
* @throws Exception
*/
privateBitmap getBitMapFromSDCard(String url)throwsException {
Bitmap bitmap = null;
String filename = MD5Util.getMD5(url);
FileInputStream fis = ctx.openFileInput(filename);
bitmap = BitmapFactory.decodeStream(fis);
returnbitmap;
}
/**
* 从缓存中读取
* @param url
* @return
* @throws Exception
*/
publicBitmap getImgFromCache(String url)throwsException {
Bitmap bitmap = null;
//从内存中读取
if(imgCache.containsKey(url)) {
synchronized(imgCache) {
SoftReference bitmapReference = imgCache.get(url);
if(null!= bitmapReference) {
bitmap = bitmapReference.get();
}
}
} else{//否则从文件中读取
bitmap = getBitMapFromSDCard(url);
//将图片保存进内存中
imgCache.put(url, newSoftReference(bitmap));
}
returnbitmap;
}
/**
* 将图片写入sdcard中
* @param bitmap
* @param url
* @throws Exception
*/
publicvoidwritePic2SDCard(Bitmap bitmap,String url)throwsException {
String filename = MD5Util.getMD5(url);
FileOutputStream fos = ctx.openFileOutput(filename, ctx.MODE_APPEND);
byte[] bitmapByte = PictureUtil.bitmap2Byte(bitmap);
ByteArrayInputStream bis = newByteArrayInputStream(bitmapByte);
intlen =0;
byte[] b =newbyte[bis.available()];
while((len = bis.read(b)) != -1) {
fos.write(b, 0, len);
}
if(null!= bis) {
bis.close();
}
if(null!= fos) {
fos.close();
}
}
}
ImgLoader(用来加在图片):
publicclassImgLoader {
privateMap> imgCache =newHashMap>();
privateContext ctx;
publicImgLoader(Context ctx) {
this.ctx = ctx;
}
privatePicManager manager =newPicManager(imgCache,ctx);
privateHandler handler =newHandler();
privateExecutorService threadPool = Executors.newFixedThreadPool(5);
publicBitmap loadImg(finalString url,finalImgCallback callback) {
//先从缓存中读取图片资源
Bitmap bitmap = null;
try{
bitmap = manager.getImgFromCache(url);;
if(null== bitmap) {
//开启线程从网络上下载
threadPool.submit(newRunnable() {//submit方法确保下载是从线程池中的线程执行
@Override
publicvoidrun() {
finalBitmap bitmapFromUrl = manager.getBitMapFromUrl(url);
try{
manager.writePic2SDCard(bitmapFromUrl,url);
} catch(Exception e) {
e.printStackTrace();
}
handler.post(newRunnable() {
@Override
publicvoidrun() {
callback.refresh(bitmapFromUrl);
}
});
}
});
} else{
}
} catch(Exception e) {
e.printStackTrace();
}
returnbitmap;
}
}
ImgCallback callback是一个接口,用来刷新界面
publicinterfaceImgCallback {
publicvoidrefresh(Bitmap bitmap);
}
最后更新:2017-04-03 19:13:18