解決ListView滑動是卡的問題解決,實現異步加載圖片解決

homepp 12年前發布 | 3K 次閱讀 需求分析 Apache Cayenne

ListView是最為常見的空間之一,現在的應用的呈現形式大多數都需要用到ListView來呈現,以列表的方式最直觀最便于操作。

那么在使用的過程中大家一定使用adapter適配器來匹配這個ListView,問題就來了,如果直接使用sampleAdapter的話,會出 現諸多的問題,諸如滾動的時候很卡,特別是每一行都有頭像啊什么的,再加上數據量一大,兼職就卡的不行,那么先來說說解決卡的問題的簡單的實現方法吧。

首先需要自己來寫一個myAdapter繼承與BaseAdapter。

然后最關鍵的是在getView方法中做到以下幾點判斷convertView是否為空,這樣可以避免每次滾動都去新建,可以節約大量資源,同時對 于圖片采用開啟線程以異步加載的方式來加載它,又可以節約一部分資源,同時,將加載下來的圖片緩存到本地,當下一次的時候首先讀取本地圖片,第一可以節約 流量,其次速度非常快(不過服務器圖片更新了這個要想好解決方案,不然你本地的圖片不會被替換掉)。最后就是在滾動時間的時候讓異步加載暫停,等手放開的 時候再加載,這樣可以保證滾動的超級流暢,不過同時會出現滾動比較大的時候圖片都還是空的沒有加載的現象,反正自己斟酌優劣吧,代碼都有哈!接下來上代碼 了

首先是主activity

package com.challen;

import java.util.Vector;

import cindy.android.test.synclistview.R;
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class TestListViewActivity extends Activity implements
        AdapterView.OnItemClickListener {

    ListView viewBookList;
    BookItemAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        viewBookList = (ListView) findViewById(R.id.viewBookList);

        adapter = new BookItemAdapter(this, viewBookList);

        viewBookList.setAdapter(adapter);
        viewBookList.setOnItemClickListener(this);
        reload();
    }

    private void reload() {
        adapter.clean();
        // loadStateView.startLoad();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2 * 1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                loadDate();
                sendMessage(REFRESH_LIST);
            }
        }).start();
    }

    public void loadDate() {
        for (int i = 0; i < 100; i++) {
            adapter.addBook("我是challen的測試異步加" + i, "1",
                    "http://ww1.sinaimg.cn/thumbnail/80ab1ad3gw1dx8tfjvbgdj.jpg");

            adapter.addBook("小美" + i, "2",
                    "http://ww2.sinaimg.cn/thumbnail/7f9fd9a9jw1dtyrqrh4mjj.jpg");

            adapter.addBook("金總" + i, "3",
                    "http://ww3.sinaimg.cn/thumbnail/9d57e8e4jw1dx6topumz5j.jpg");

            adapter.addBook("創意鋪子" + i, "4",
                    "http://www.pfwx.com/files/article/image/3/3237/3237s.jpg");

            adapter.addBook("人名日報" + i, "5",
                    "http://ww2.sinaimg.cn/thumbnail/9263d293jw1dx8snx58s7j.jpg");

            adapter.addBook("名字是亂明的" + i, "6",
                    "http://tp1.sinaimg.cn/1660452532/50/5646449168/0");
            adapter.addBook("帥哥即將出現" + i, "7",
                    "http://p1.qhimg.com/t01a869bb64c7f3d8c6.png");
            adapter.addBook("注意了哦" + i, "8",
                    "http://www.baidu.com/img/baidu_jgylogo3.gif");
            adapter.addBook("來拉" + i, "9",
                    "http://tp4.sinaimg.cn/2190322767/50/5605436918/1");
            adapter.addBook("這個就是我啦" + i, "10",
                    "http://avatar.csdn.net/E/7/2/3_jkingcl.jpg");

        }
    }

    private static final int REFRESH_LIST = 0x10001;
    public static final int SHOW_STR_TOAST = 0;
    public static final int SHOW_RES_TOAST = 1;

    private Handler pichandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (!Thread.currentThread().isInterrupted()) {
                handleOtherMessage(msg.what);
            }
        }
    };

    public void sendMessage(int flag) {
        pichandler.sendEmptyMessage(flag);
    }

    protected void handleOtherMessage(int flag) {
        switch (flag) {
        case REFRESH_LIST:
            adapter.notifyDataSetChanged();
        default:
            break;
        }
    }

    @Override
    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        // TODO Auto-generated method stub

    }

    public class BookItemAdapter extends BaseAdapter {

        public class BookModel {
            public String book_id;
            public String out_book_url;
            public String author;
            public String book_state_s;
            public String leading_role;
            public String update_time;
            public String book_name;
            public String out_book_pic;
            public String sort_id;
            public String last_update_section_title;
            public String last_update_section_url;
            public String introduction;
        }

        private LayoutInflater mInflater;
        private Vector<BookModel> mModels = new Vector<BookModel>();
        private ListView mListView;
        SyncImageLoader syncImageLoader;

        public BookItemAdapter(Context context, ListView listView) {
            mInflater = LayoutInflater.from(context);
            syncImageLoader = new SyncImageLoader();
            mListView = listView;

            /*
             *
             * 這一句話取消掉注釋的話,那么能更加的節省資源,不過體驗稍微有點,
             * 你滑動的時候不會讀取圖片,當手放開后才開始度圖片速度更快,你們可以試一試
             * */

            // mListView.setOnScrollListener(onScrollListener);
        }

        public void addBook(String book_name, String author, String out_book_pic) {
            BookModel model = new BookModel();
            model.book_name = book_name;
            model.author = author;
            model.out_book_pic = out_book_pic;
            mModels.add(model);
        }

        public void clean() {
            mModels.clear();
        }

        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return mModels.size();
        }

        @Override
        public Object getItem(int position) {
            if (position >= getCount()) {
                return null;
            }
            return mModels.get(position);
        }

        @Override
        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = mInflater.inflate(R.layout.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, model.author);
            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:
                    syncImageLoader.lock();
                    break;
                case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
                    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

            }
        };
    }

}

其次是實現異步加載和緩存圖片的功能代碼loader.java
package com.challen;

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,String author1) {
        final OnImageLoadListener mListener = listener;
        final String mImageUrl = imageUrl;
        final Integer mt = t;
        final String author = author1;

        new Thread(new Runnable() {

            @Override
            public void run() {
                if(!mAllowLoad){
                    synchronized (lock) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }

                if(mAllowLoad && firstLoad){
                    loadImage(mImageUrl, mt, mListener,author);
                }

                if(mAllowLoad && mt <= mStopLoadLimit && mt >= mStartLoadLimit){
                    loadImage(mImageUrl, mt, mListener,author);
                }
            }

        }).start();
    }

    private void loadImage(final String mImageUrl,final Integer mt,final OnImageLoadListener mListener,final String author){

        if (imageCache.containsKey(mImageUrl)) {  
            System.out.println("drawable");
            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,author);
            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,String author) throws IOException {
        //是否SD卡可用
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            //檢查是或有保存圖片的文件夾,沒有就穿件一個
            String FileUrl = Environment.getExternalStorageDirectory()+"/TestSyncListView/";
            File folder = new File(FileUrl);
            if(!folder.exists()){
                folder.mkdir();
            }
            File f = new File(FileUrl+author+".jpg");
            //SD卡中是否有該文件,有則直接讀取返回
            if(f.exists()){
                FileInputStream fis = new FileInputStream(f);
                Drawable d = Drawable.createFromStream(fis, "src");
                return d;
            }
            //沒有的話則去連接下載,并寫入到SD卡中
            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,author);
        }
        //SD卡不可用則直接加載使用
        else{
            URL m = new URL(url);
            InputStream i = (InputStream) m.getContent();
            Drawable d = Drawable.createFromStream(i, "src");
            return d;
        }

    }
}
 本文由用戶 homepp 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!