Android ListView 异步加载图片

写这篇文章并不是教大家怎么样用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


部分代码如下:

Java代码
  1. @Override
  2. public View getView(int position, View convertView, ViewGroup parent) {
  3.         if(convertView == null){
  4.                 convertView = mInflater.inflate(R.layout.book_item_adapter, null);
  5.         }
  6.         BookModel model = mModels.get(position);
  7.         convertView.setTag(position);
  8.         ImageView iv = (ImageView) convertView.findViewById(R.id.sItemIcon);
  9.         TextView sItemTitle =  (TextView) convertView.findViewById(R.id.sItemTitle);
  10.         TextView sItemInfo =  (TextView) convertView.findViewById(R.id.sItemInfo);
  11.         sItemTitle.setText(model.book_name);
  12.         sItemInfo.setText(model.out_book_url);
  13.         iv.setBackgroundResource(R.drawable.rc_item_bg);
  14.         syncImageLoader.loadImage(position,model.out_book_pic,imageLoadListener);
  15.         return  convertView;
  16. }

  17. SyncImageLoader.OnImageLoadListener imageLoadListener = new SyncImageLoader.OnImageLoadListener(){

  18.         @Override
  19.         public void onImageLoad(Integer t, Drawable drawable) {
  20.                 //BookModel model = (BookModel) getItem(t);
  21.                 View view = mListView.findViewWithTag(t);
  22.                 if(view != null){
  23.                         ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
  24.                         iv.setBackgroundDrawable(drawable);
  25.                 }
  26.         }
  27.         @Override
  28.         public void onError(Integer t) {
  29.                 BookModel model = (BookModel) getItem(t);
  30.                 View view = mListView.findViewWithTag(model);
  31.                 if(view != null){
  32.                         ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
  33.                         iv.setBackgroundResource(R.drawable.rc_item_bg);
  34.                 }
  35.         }
  36.         
  37. };

  38. public void loadImage(){
  39.         int start = mListView.getFirstVisiblePosition();
  40.         int end =mListView.getLastVisiblePosition();
  41.         if(end >= getCount()){
  42.                 end = getCount() -1;
  43.         }
  44.         syncImageLoader.setLoadLimit(start, end);
  45.         syncImageLoader.unlock();
  46. }

  47. AbsListView.OnScrollListener onScrollListener = new AbsListView.OnScrollListener() {
  48.         
  49.         @Override
  50.         public void onScrollStateChanged(AbsListView view, int scrollState) {
  51.                 switch (scrollState) {
  52.                         case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
  53.                                 DebugUtil.debug("SCROLL_STATE_FLING");
  54.                                 syncImageLoader.lock();
  55.                                 break;
  56.                         case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
  57.                                 DebugUtil.debug("SCROLL_STATE_IDLE");
  58.                                 loadImage();
  59.                                 //loadImage();
  60.                                 break;
  61.                         case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
  62.                                 syncImageLoader.lock();
  63.                                 break;

  64.                         default:
  65.                                 break;
  66.                 }
  67.                
  68.         }
  69.         
  70.         @Override
  71.         public void onScroll(AbsListView view, int firstVisibleItem,
  72.                         int visibleItemCount, int totalItemCount) {
  73.                 // TODO Auto-generated method stub
  74.                
  75.         }
  76. };
复制代码
package cindy.android.test.synclistview;
Syncimageloader代码
  1. import java.io.DataInputStream;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. import java.lang.ref.SoftReference;
  8. import java.net.URL;
  9. import java.util.HashMap;

  10. import android.graphics.drawable.Drawable;
  11. import android.os.Environment;
  12. import android.os.Handler;

  13. public class SyncImageLoader {

  14.         private Object lock = new Object();
  15.         
  16.         private boolean mAllowLoad = true;
  17.         
  18.         private boolean firstLoad = true;
  19.         
  20.         private int mStartLoadLimit = 0;
  21.         
  22.         private int mStopLoadLimit = 0;
  23.         
  24.         final Handler handler = new Handler();
  25.         
  26.         private HashMap<string, softreference> imageCache = new HashMap<string, softreference>();   
  27.         
  28.         public interface OnImageLoadListener {
  29.                 public void onImageLoad(Integer t, Drawable drawable);
  30.                 public void onError(Integer t);
  31.         }
  32.         
  33.         public void setLoadLimit(int startLoadLimit,int stopLoadLimit){
  34.                 if(startLoadLimit > stopLoadLimit){
  35.                         return;
  36.                 }
  37.                 mStartLoadLimit = startLoadLimit;
  38.                 mStopLoadLimit = stopLoadLimit;
  39.         }
  40.         
  41.         public void restore(){
  42.                 mAllowLoad = true;
  43.                 firstLoad = true;
  44.         }
  45.                
  46.         public void lock(){
  47.                 mAllowLoad = false;
  48.                 firstLoad = false;
  49.         }
  50.         
  51.         public void unlock(){
  52.                 mAllowLoad = true;
  53.                 synchronized (lock) {
  54.                         lock.notifyAll();
  55.                 }
  56.         }

  57.         public void loadImage(Integer t, String imageUrl,
  58.                         OnImageLoadListener listener) {
  59.                 final OnImageLoadListener mListener = listener;
  60.                 final String mImageUrl = imageUrl;
  61.                 final Integer mt = t;
  62.                
  63.                 new Thread(new Runnable() {

  64.                         @Override
  65.                         public void run() {
  66.                                 if(!mAllowLoad){
  67.                                         DebugUtil.debug("prepare to load");
  68.                                         synchronized (lock) {
  69.                                                 try {
  70.                                                         lock.wait();
  71.                                                 } catch (InterruptedException e) {
  72.                                                         // TODO Auto-generated catch block
  73.                                                         e.printStackTrace();
  74.                                                 }
  75.                                         }
  76.                                 }
  77.                                 
  78.                                 if(mAllowLoad && firstLoad){
  79.                                         loadImage(mImageUrl, mt, mListener);
  80.                                 }
  81.                                 
  82.                                 if(mAllowLoad && mt <= mStopLoadLimit && mt >= mStartLoadLimit){
  83.                                         loadImage(mImageUrl, mt, mListener);
  84.                                 }
  85.                         }

  86.                 }).start();
  87.         }
  88.         
  89.         private void loadImage(final String mImageUrl,final Integer mt,final OnImageLoadListener mListener){
  90.                
  91.                 if (imageCache.containsKey(mImageUrl)) {  
  92.             SoftReference softReference = imageCache.get(mImageUrl);  
  93.             final Drawable d = softReference.get();  
  94.             if (d != null) {  
  95.                     handler.post(new Runnable() {
  96.                                     @Override
  97.                                     public void run() {
  98.                                             if(mAllowLoad){
  99.                                                     mListener.onImageLoad(mt, d);
  100.                                             }
  101.                                     }
  102.                             });
  103.                 return;  
  104.             }  
  105.         }  
  106.                 try {
  107.                         final Drawable d = loadImageFromUrl(mImageUrl);
  108.                         if(d != null){
  109.                 imageCache.put(mImageUrl, new SoftReference(d));
  110.                         }
  111.                         handler.post(new Runnable() {
  112.                                 @Override
  113.                                 public void run() {
  114.                                         if(mAllowLoad){
  115.                                                 mListener.onImageLoad(mt, d);
  116.                                         }
  117.                                 }
  118.                         });
  119.                 } catch (IOException e) {
  120.                         handler.post(new Runnable() {
  121.                                 @Override
  122.                                 public void run() {
  123.                                         mListener.onError(mt);
  124.                                 }
  125.                         });
  126.                         e.printStackTrace();
  127.                 }
  128.         }

  129.         public static Drawable loadImageFromUrl(String url) throws IOException {
  130.                 DebugUtil.debug(url);
  131.                 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
  132.                         File f = new File(Environment.getExternalStorageDirectory()+"/TestSyncListView/"+MD5.getMD5(url));
  133.                         if(f.exists()){
  134.                                 FileInputStream fis = new FileInputStream(f);
  135.                                 Drawable d = Drawable.createFromStream(fis, "src");
  136.                                 return d;
  137.                         }
  138.                         URL m = new URL(url);
  139.                         InputStream i = (InputStream) m.getContent();
  140.                         DataInputStream in = new DataInputStream(i);
  141.                         FileOutputStream out = new FileOutputStream(f);
  142.                         byte[] buffer = new byte[1024];
  143.                         int   byteread=0;
  144.                         while ((byteread = in.read(buffer)) != -1) {
  145.                                 out.write(buffer, 0, byteread);
  146.                         }
  147.                         in.close();
  148.                         out.close();
  149.                         Drawable d = Drawable.createFromStream(i, "src");
  150.                         return loadImageFromUrl(url);
  151.                 }else{
  152.                         URL m = new URL(url);
  153.                         InputStream i = (InputStream) m.getContent();
  154.                         Drawable d = Drawable.createFromStream(i, "src");
  155.                         return d;
  156.                 }
  157.                
  158.         }
  159. }

复制代码
为了让大家更好的理解,我添加了源代码例子,还特地美化了一下UI

91db09e0-0462-31c8-82c5-cc9f9003de2f.png
除了本身已有的弱引用缓存图片,我还添加了本地SD卡缓存图片(这两种缓存方法各有好处,如果图片经常变化建议内存缓存图片,如果是不经常修改的图片建议SD卡缓存)

欢迎大家拍砖讨论
TestSyncListView.rar(147.82 KB, 下载次数: 1836)


转自:
http://www.iteye.com/topic/1118828
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值