解决ListView滑动是卡的问题解决,实现异步加载图片解决
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; } } }