android异步图片加载三之handler+线程池+消息队列模式+缓存
假象现在有这样一个需求:
????? 一个微博客户端或者多媒体客户端需要从服务端拉取一些数据,该数据中包含了很多图片,如果不用异步加载方式,可能会使主线程阻塞导致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方法确保下载是从线程池中的线程执行@Overridepublic void run() {final Bitmap bitmapFromUrl = manager.getBitMapFromUrl(url);try {manager.writePic2SDCard(bitmapFromUrl,url);} catch (Exception e) {e.printStackTrace();}handler.post(new Runnable() {@Overridepublic void run() {callback.refresh(bitmapFromUrl);}});}});} else {}} catch (Exception e) {e.printStackTrace();}return bitmap;}}
?ImgCallback callback是一个接口,用来刷新界面
public interface ImgCallback {public void refresh(Bitmap bitmap);}
?