您的位置:首页 > 移动开发 > Android开发

Android ListView 异步加载图片

2013-05-10 08:36 232 查看
写这篇文章并不是教大家怎么样用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

[align=left]部分代码如下:[/align]

[align=left]Java代码
[/align]

@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;
[b]Syncimageloader代码
[/b]

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



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

[align=left]欢迎大家拍砖讨论[/align]


TestSyncListView.rar(147.82
KB, 下载次数: 1836)

转自:
http://www.iteye.com/topic/1118828
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: