当前位置: 移动技术网 > IT编程>移动开发>Android > Android ListView异步加载图片方法详解

Android ListView异步加载图片方法详解

2019年07月24日  | 移动技术网IT编程  | 我要评论

谢学志,乔绍恒 痞子英雄,清爱阁

本文实例讲述了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程序设计有所帮助。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网