Android实现异步加载图片
麦洛开通博客以来,有一段时间没有更新博文了.主要是麦洛这段时间因项目开发实在太忙了.今天周六还在公司加班,苦逼程序猿都是这样生活的.
今天在做项目的时候,有一个实现异步加载图片的功能,虽然比较简单但还是记录一下吧.因为麦洛之前实现异步加载图片都是使用了asyntask这个api,继续这个类,实现起来非常简单也很方便.在doinbackground()方法里实现下载逻辑.具体实现如下
实现逻辑是:先从内存中读取,如果内存中有这张图片,则直接使用;如果内存没有再到sdcard上读取,如果有则显示;如果sdcard上还没有则到网络上读取.内存中开启缓存是参考了网上的实现.麦洛在这里非常感谢喜欢分享的程序猿们.
public class imagedownloader extends asynctask<string, integer, object> { private static final string tag = "imagedownloader"; // 为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在listview时来回滚动) private map<string, softreference<drawable>> imagecache = new hashmap<string, softreference<drawable>>(); /** * 显示图片的控件 */ private imageview mimageview; public imagedownloader(imageview image) { mimageview = image; } @override protected void onpreexecute() { super.onpreexecute(); } @override protected object doinbackground(string... params) { // log.i("imagedownloader", "loading image..."); string url = params[0]; drawable drawable = null; try { if (!"".equals(url) && url != null) { string filename = url.hashcode()+".jpg"; // 如果缓存过就从缓存中取出数据 if (imagecache.containskey(filename)) { softreference<drawable> softreference = imagecache.get(filename); drawable = softreference.get(); if (drawable != null) { return drawable; } } file dir = new file(fileconstant.image_file_path); if (!dir.exists()) { boolean m = dir.mkdirs(); } file file = new file(dir, filename); if (file.exists() && file.length() > 0) { log.i(tag, "load image from sd card"); // 如果文件存在则直接读取sdcard drawable = readfromsdcard(file); } else { //file.createnewfile(); log.i(tag, "load image from network"); url imageurl = new url(url); // 写入sdcard if (environment.getexternalstoragestate().equals(environment.media_mounted)) { saveimagefile(imageurl, file); drawable = drawable.createfromstream(new fileinputstream(file), filename); }else{ //直接从流读取 drawable = drawable.createfromstream(imageurl.openstream(), filename); } } if(drawable!=null){ //保存在缓存中 imagecache.put(filename, new softreference<drawable>(drawable)); } } } catch (exception e) { e.printstacktrace(); } return drawable; } /** * save image */ private void saveimagefile(url url, file file) { fileoutputstream out = null; inputstream in = null; try { file.deleteonexit(); out = new fileoutputstream(file); in = url.openstream(); byte[] buf = new byte[1024]; int len = -1; while((len = in.read(buf))!=-1){ out.write(buf, 0, len); out.flush(); } } catch (exception e) { e.printstacktrace(); } finally { if(out!=null){ try { out.close(); } catch (ioexception e) { e.printstacktrace(); } } if(in!=null){ try { in.close(); } catch (ioexception e) { e.printstacktrace(); } } } } /** * 从sdcard中获取图片 */ private drawable readfromsdcard(file file) throws exception { fileinputstream in = new fileinputstream(file); return drawable.createfromstream(in, file.getname()); } @override protected void onpostexecute(object result) { super.onpostexecute(result); drawable drawable = (drawable) result; if (mimageview != null && drawable != null) { mimageview.setbackgrounddrawable(drawable); } } @override protected void onprogressupdate(integer... values) { super.onprogressupdate(values); } @override protected void oncancelled() { super.oncancelled(); } }
使用时:
imagedownloader loader = new imagedownloader(imageview); loader.execute(url);
其实这样的话,还有一些隐患的,就是说这个类实现还是有些问题的.比如每次都在imageview中设置网络上的图片时,其实是没有使用到这个类里面的内存缓存的,就是imagecache
map<string, softreference<drawable>> imagecache = new hashmap<string, softreference<drawable>>();
因为每次设置imageview的时候,都是new了一个imagedownloader的对象.所以每个imagedownloader对象里面都是独立的一个imagecache.
另外,asyntask也是一个线程.而每次使用都开一个线程来load 图片,对线程个数没有进行显示,毕竟线程数目还是有限制的.
所以麦洛今天发现了这个问题,于是参考了别人的实现,使用了线程池,实现逻辑也上面的代码一样,先从内存读取,如果没有到sdcard读取,如果还是没有,则是网络读取;实现没有使用asyntask,具体代码如下:
/** * 异步加载图片,并将图片设置到imageview控件中 */ public class imagedownloader extends asynctask<string, integer, object> { private static final string tag = "imagedownloader"; // 为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在listview时来回滚动) private map<string, softreference<drawable>> imagecache = new hashmap<string, softreference<drawable>>(); /** * 显示图片的控件 */ private imageview mimageview; public imagedownloader(imageview image) { mimageview = image; } @override protected void onpreexecute() { super.onpreexecute(); } @override protected object doinbackground(string... params) { // log.i("imagedownloader", "loading image..."); string url = params[0]; drawable drawable = null; try { if (!"".equals(url) && url != null) { string filename = url.hashcode()+".jpg"; // 如果缓存过就从缓存中取出数据 if (imagecache.containskey(filename)) { softreference<drawable> softreference = imagecache.get(filename); drawable = softreference.get(); if (drawable != null) { return drawable; } } file dir = new file(fileconstant.image_file_path); if (!dir.exists()) { boolean m = dir.mkdirs(); } file file = new file(dir, filename); if (file.exists() && file.length() > 0) { log.i(tag, "load image from sd card"); // 如果文件存在则直接读取sdcard drawable = readfromsdcard(file); } else { //file.createnewfile(); log.i(tag, "load image from network"); url imageurl = new url(url); // 写入sdcard if (environment.getexternalstoragestate().equals(environment.media_mounted)) { saveimagefile(imageurl, file); drawable = drawable.createfromstream(new fileinputstream(file), filename); }else{ //直接从流读取 drawable = drawable.createfromstream(imageurl.openstream(), filename); } } if(drawable!=null){ //保存在缓存中 imagecache.put(filename, new softreference<drawable>(drawable)); } } } catch (exception e) { e.printstacktrace(); } return drawable; } /** * save image */ private void saveimagefile(url url, file file) { fileoutputstream out = null; inputstream in = null; try { file.deleteonexit(); out = new fileoutputstream(file); in = url.openstream(); byte[] buf = new byte[1024]; int len = -1; while((len = in.read(buf))!=-1){ out.write(buf, 0, len); out.flush(); } } catch (exception e) { e.printstacktrace(); } finally { if(out!=null){ try { out.close(); } catch (ioexception e) { e.printstacktrace(); } } if(in!=null){ try { in.close(); } catch (ioexception e) { e.printstacktrace(); } } } } /** * 从sdcard中获取图片 */ private drawable readfromsdcard(file file) throws exception { fileinputstream in = new fileinputstream(file); return drawable.createfromstream(in, file.getname()); } @override protected void onpostexecute(object result) { super.onpostexecute(result); drawable drawable = (drawable) result; if (mimageview != null && drawable != null) { mimageview.setbackgrounddrawable(drawable); } } @override protected void onprogressupdate(integer... values) { super.onprogressupdate(values); } @override protected void oncancelled() { super.oncancelled(); } }
这个imagedownloader2的使用也很简单
public class imageutil { /** * image loader */ static imagedownloader2 loader = null; /** * load image */ public static void loadimage(string url,final imageview imageview){ if(loader == null){ loader = new imagedownloader2(); } loader.loaddrawable(url, new imagecallback() { @override public void imageloaded(drawable imagedrawable) { if(imagedrawable!=null){ imageview.setbackgrounddrawable(imagedrawable); } } }); } }
每次在使用是需要调用imageutil.loadimage(url,imageview)将图片url已经需要显示图片的控件imageview的引用传入就可以了.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。