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代码 

@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;

Syncimageloader代码

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> imageCache = new HashMap<string, softreference>();   
        
        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 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(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;
                }
                
        }
}


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


91db09e0-0462-31c8-82c5-cc9f9003de2f.png

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

转自:http://www.iteye.com/topic/1118828


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值