您的位置:首页 > 移动开发 > Android开发

android异步图片加载三之handler+线程池+消息队列模式+缓存

2013-06-04 13:46 651 查看
假象现在有这样一个需求:

一个微博客户端或者多媒体客户端需要从服务端拉取一些数据,该数据中包含了很多图片,如果不用异步加载方式,可能会使主线程阻塞导致ANR异常,但是异步加载后如果每次都通过网络去下载图片,性能上会差很多,而且也会浪费流量,导致用户的不满,故现在增加一个缓存用来存储图片,缓存中包含内存存储和sdcard存储。先从缓存中去,在缓存中先从内存中取出,如果内存中没有再从sdcard去,如果sdcard中存在则直接返回该图片资源并放入内存中,如果两者都没有则从网络上下载,下载后并放入sdcard中供下次使用,这样就节约了资源开销,下面是主要代码:

PicManager(用来处理图片的操作):

public class PicManager {

private Map<String,SoftReference<Bitmap>> imgCache ;
private Context ctx;

public PicManager(Map<String,SoftReference<Bitmap>> imgCache,Context ctx) {
this.ctx = ctx;
this.imgCache = imgCache;
}

/**
* 从网络上下载
* @param url
* @return
*/
public Bitmap getBitMapFromUrl(String url) {
Bitmap bitmap = null;
URL u =null;
HttpURLConnection conn = null;
InputStream is = null;
try {
u = new URL(url);
conn = (HttpURLConnection)u.openConnection();
is = conn.getInputStream();
bitmap = BitmapFactory.decodeStream(is);
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}

/**
* 从文件中读取
* @return
* @throws Exception
*/
private Bitmap getBitMapFromSDCard(String url) throws Exception {
Bitmap bitmap = null;
String filename = MD5Util.getMD5(url);
FileInputStream fis = ctx.openFileInput(filename);
bitmap = BitmapFactory.decodeStream(fis);
return bitmap;
}

/**
* 从缓存中读取
* @param url
* @return
* @throws Exception
*/
public Bitmap getImgFromCache(String url) throws Exception {
Bitmap bitmap = null;
//从内存中读取
if(imgCache.containsKey(url)) {
synchronized (imgCache) {
SoftReference<Bitmap> bitmapReference = imgCache.get(url);
if(null != bitmapReference) {
bitmap = bitmapReference.get();
}
}
} else {//否则从文件中读取
bitmap = getBitMapFromSDCard(url);
//将图片保存进内存中
imgCache.put(url, new SoftReference<Bitmap>(bitmap));
}
return bitmap;
}

/**
* 将图片写入sdcard中
* @param bitmap
* @param url
* @throws Exception
*/
public void writePic2SDCard(Bitmap bitmap,String url) throws Exception {
String filename = MD5Util.getMD5(url);
FileOutputStream fos = ctx.openFileOutput(filename, ctx.MODE_APPEND);
byte[] bitmapByte = PictureUtil.bitmap2Byte(bitmap);
ByteArrayInputStream bis = new ByteArrayInputStream(bitmapByte);
int len = 0;
byte[] b = new byte[bis.available()];
while((len = bis.read(b)) != -1) {
fos.write(b, 0, len);
}
if(null != bis) {
bis.close();
}
if(null != fos) {
fos.close();
}
}
}


ImgLoader(用来加载图片):

public class ImgLoader {

private Map<String,SoftReference<Bitmap>> imgCache = new HashMap<String,SoftReference<Bitmap>>();
private Context ctx;

public ImgLoader(Context ctx) {
this.ctx = ctx;
}

private PicManager manager = new PicManager(imgCache,ctx);
private Handler handler = new Handler();

private ExecutorService threadPool = Executors.newFixedThreadPool(5);

public Bitmap loadImg(final String url,final ImgCallback callback) {

//先从缓存中读取图片资源
Bitmap bitmap = null;
try {
bitmap = manager.getImgFromCache(url);;

if(null == bitmap) {
//开启线程从网络上下载
threadPool.submit(new Runnable() {//submit方法确保下载是从线程池中的线程执行
@Override
public void run() {
final Bitmap bitmapFromUrl = manager.getBitMapFromUrl(url);
try {
manager.writePic2SDCard(bitmapFromUrl,url);
} catch (Exception e) {
e.printStackTrace();
}
handler.post(new Runnable() {
@Override
public void run() {
callback.refresh(bitmapFromUrl);
}
});
}
});
} else {

}
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}

}


ImgCallback callback是一个接口,用来刷新界面:

public interface ImgCallback {

public void refresh(Bitmap bitmap);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐