Android ListView异步加载图片方法详解
本文实例讲述了android listview异步加载图片方法。分享给大家供大家参考,具体如下:
先说说这篇文章的优点把,开启线程异步加载图片,然后刷新ui显示图片,而且通过弱引用缓存网络加载的图片,节省了再次连接网络的开销。
这样做无疑是非常可取的方法,但是加载图片时仍然会感觉到轻微的卡屏现象,特别是listview里的item在进行快速滑动的时候。
我找了一下原因,可能是在listview快速滑动屏幕的时候划过的item太多 而且每次调用getview方法后就会异步的在过去某个时间内用handler刷新一下ui,
如果在同一时间调用handler刷新ui次数多了就会造成这样的卡屏现象。
后来又一想,其实我们完全没有必要在listview正在滑动的时候去后台加载图片(不管这是图片是在缓存里还是在网络上),这样无疑造成了很大的资源浪费。
我们只需要在listview滑动停止之后再去加载listview里面显示的几个item里面的图片就好了。
根据以上想法,我做了一些设计改造:
1.在adapter 的 getview方法里面启动加载图片的thread,如果listview在滑动则wait
2.监听listview滑动停止事件,获得listview显示的item的最上面和最下面的序号,并唤醒所有加载图片的thread,判断加载图片的序号是否是在范围内,如果是则继续加载,如果不是则结束thread
部分代码如下:
@override public view getview(int position, view convertview, viewgroup parent) { if(convertview == null){ convertview = minflater.inflate(r.layout.book_item_adapter, null); } bookmodel model = mmodels.get(position); convertview.settag(position); imageview iv = (imageview) convertview.findviewbyid(r.id.sitemicon); textview sitemtitle = (textview) convertview.findviewbyid(r.id.sitemtitle); textview siteminfo = (textview) convertview.findviewbyid(r.id.siteminfo); sitemtitle.settext(model.book_name); siteminfo.settext(model.out_book_url); iv.setbackgroundresource(r.drawable.rc_item_bg); syncimageloader.loadimage(position,model.out_book_pic,imageloadlistener); return convertview; } syncimageloader.onimageloadlistener imageloadlistener = new syncimageloader.onimageloadlistener(){ @override public void onimageload(integer t, drawable drawable) { //bookmodel model = (bookmodel) getitem(t); view view = mlistview.findviewwithtag(t); if(view != null){ imageview iv = (imageview) view.findviewbyid(r.id.sitemicon); iv.setbackgrounddrawable(drawable); } } @override public void onerror(integer t) { bookmodel model = (bookmodel) getitem(t); view view = mlistview.findviewwithtag(model); if(view != null){ imageview iv = (imageview) view.findviewbyid(r.id.sitemicon); iv.setbackgroundresource(r.drawable.rc_item_bg); } } }; public void loadimage(){ int start = mlistview.getfirstvisibleposition(); int end =mlistview.getlastvisibleposition(); if(end >= getcount()){ end = getcount() -1; } syncimageloader.setloadlimit(start, end); syncimageloader.unlock(); } abslistview.onscrolllistener onscrolllistener = new abslistview.onscrolllistener() { @override public void onscrollstatechanged(abslistview view, int scrollstate) { switch (scrollstate) { case abslistview.onscrolllistener.scroll_state_fling: debugutil.debug("scroll_state_fling"); syncimageloader.lock(); break; case abslistview.onscrolllistener.scroll_state_idle: debugutil.debug("scroll_state_idle"); loadimage(); //loadimage(); break; case abslistview.onscrolllistener.scroll_state_touch_scroll: syncimageloader.lock(); break; default: break; } } @override public void onscroll(abslistview view, int firstvisibleitem, int visibleitemcount, int totalitemcount) { // todo auto-generated method stub } };
package cindy.android.test.synclistview; import java.io.datainputstream; import java.io.file; import java.io.fileinputstream; import java.io.fileoutputstream; import java.io.ioexception; import java.io.inputstream; import java.lang.ref.softreference; import java.net.url; import java.util.hashmap; import android.graphics.drawable.drawable; import android.os.environment; import android.os.handler; public class syncimageloader { private object lock = new object(); private boolean mallowload = true; private boolean firstload = true; private int mstartloadlimit = 0; private int mstoploadlimit = 0; final handler handler = new handler(); private hashmap<string, softreference<drawable>> imagecache = new hashmap<string, softreference<drawable>>(); public interface onimageloadlistener { public void onimageload(integer t, drawable drawable); public void onerror(integer t); } public void setloadlimit(int startloadlimit,int stoploadlimit){ if(startloadlimit > stoploadlimit){ return; } mstartloadlimit = startloadlimit; mstoploadlimit = stoploadlimit; } public void restore(){ mallowload = true; firstload = true; } public void lock(){ mallowload = false; firstload = false; } public void unlock(){ mallowload = true; synchronized (lock) { lock.notifyall(); } } public void loadimage(integer t, string imageurl, onimageloadlistener listener) { final onimageloadlistener mlistener = listener; final string mimageurl = imageurl; final integer mt = t; new thread(new runnable() { @override public void run() { if(!mallowload){ debugutil.debug("prepare to load"); synchronized (lock) { try { lock.wait(); } catch (interruptedexception e) { // todo auto-generated catch block e.printstacktrace(); } } } if(mallowload && firstload){ loadimage(mimageurl, mt, mlistener); } if(mallowload && mt <= mstoploadlimit && mt >= mstartloadlimit){ loadimage(mimageurl, mt, mlistener); } } }).start(); } private void loadimage(final string mimageurl,final integer mt,final onimageloadlistener mlistener){ if (imagecache.containskey(mimageurl)) { softreference<drawable> softreference = imagecache.get(mimageurl); final drawable d = softreference.get(); if (d != null) { handler.post(new runnable() { @override public void run() { if(mallowload){ mlistener.onimageload(mt, d); } } }); return; } } try { final drawable d = loadimagefromurl(mimageurl); if(d != null){ imagecache.put(mimageurl, new softreference<drawable>(d)); } handler.post(new runnable() { @override public void run() { if(mallowload){ mlistener.onimageload(mt, d); } } }); } catch (ioexception e) { handler.post(new runnable() { @override public void run() { mlistener.onerror(mt); } }); e.printstacktrace(); } } public static drawable loadimagefromurl(string url) throws ioexception { debugutil.debug(url); if(environment.getexternalstoragestate().equals(environment.media_mounted)){ file f = new file(environment.getexternalstoragedirectory()+"/testsynclistview/"+md5.getmd5(url)); if(f.exists()){ fileinputstream fis = new fileinputstream(f); drawable d = drawable.createfromstream(fis, "src"); return d; } url m = new url(url); inputstream i = (inputstream) m.getcontent(); datainputstream in = new datainputstream(i); fileoutputstream out = new fileoutputstream(f); byte[] buffer = new byte[1024]; int byteread=0; while ((byteread = in.read(buffer)) != -1) { out.write(buffer, 0, byteread); } in.close(); out.close(); drawable d = drawable.createfromstream(i, "src"); return loadimagefromurl(url); }else{ url m = new url(url); inputstream i = (inputstream) m.getcontent(); drawable d = drawable.createfromstream(i, "src"); return d; } } }
除了本身已有的弱引用缓存图片,我还添加了本地sd卡缓存图片(这两种缓存方法各有好处,如果图片经常变化建议内存缓存图片,如果是不经常修改的图片建议sd卡缓存)
更多关于android相关内容感兴趣的读者可查看本站专题:《android开发入门与进阶教程》、《android多媒体操作技巧汇总(音频,视频,录音等)》、《android基本组件用法总结》、《android视图view技巧总结》、《android布局layout技巧总结》及《android控件用法总结》
希望本文所述对大家android程序设计有所帮助。