解决ListView滑动时卡的问题,实现异步加载图片解决

ListView是最为常见的空间之一,现在的应用的呈现形式大多数都需要用到ListView来呈现,以列表的方式最直观最便于操作。

那么在使用的过程中大家一定使用adapter适配器来匹配这个ListView,问题就来了,如果直接使用sampleAdapter的话,会出现诸多的问题,诸如滚动的时候很卡,特别是每一行都有头像啊什么的,再加上数据量一大,兼职就卡的不行,那么先来说说解决卡的问题的简单的实现方法吧。

首先需要自己来写一个myAdapter继承与BaseAdapter。

然后最关键的是在getView方法中做到以下几点判断convertView是否为空,这样可以避免每次滚动都去新建,可以节约大量资源,同时对于图片采用开启线程以异步加载的方式来加载它,又可以节约一部分资源,同时,将加载下来的图片缓存到本地,当下一次的时候首先读取本地图片,第一可以节约流量,其次速度非常快(不过服务器图片更新了这个要想好解决方案,不然你本地的图片不会被替换掉)。最后就是在滚动时间的时候让异步加载暂停,等手放开的时候再加载,这样可以保证滚动的超级流畅,不过同时会出现滚动比较大的时候图片都还是空的没有加载的现象,反正自己斟酌优劣吧,代码都有哈!接下来上代码了

首先是主activity

  1. package com.challen;
  2. import java.util.Vector;
  3. import cindy.android.test.synclistview.R;
  4. import android.app.Activity;
  5. import android.content.Context;
  6. import android.graphics.drawable.Drawable;
  7. import android.os.Bundle;
  8. import android.os.Handler;
  9. import android.os.Message;
  10. import android.view.LayoutInflater;
  11. import android.view.View;
  12. import android.view.ViewGroup;
  13. import android.widget.AbsListView;
  14. import android.widget.AdapterView;
  15. import android.widget.BaseAdapter;
  16. import android.widget.ImageView;
  17. import android.widget.ListView;
  18. import android.widget.TextView;
  19. public class TestListViewActivity extends Activity implements
  20. AdapterView.OnItemClickListener {
  21. ListView viewBookList;
  22. BookItemAdapter adapter;
  23. @Override
  24. protected void onCreate(Bundle savedInstanceState) {
  25. // TODO Auto-generated method stub
  26. super.onCreate(savedInstanceState);
  27. setContentView(R.layout.main);
  28. viewBookList = (ListView) findViewById(R.id.viewBookList);
  29. adapter = new BookItemAdapter(this, viewBookList);
  30. viewBookList.setAdapter(adapter);
  31. viewBookList.setOnItemClickListener(this);
  32. reload();
  33. }
  34. private void reload() {
  35. adapter.clean();
  36. // loadStateView.startLoad();
  37. new Thread(new Runnable() {
  38. @Override
  39. public void run() {
  40. try {
  41. Thread.sleep(2 * 1000);
  42. } catch (InterruptedException e) {
  43. // TODO Auto-generated catch block
  44. e.printStackTrace();
  45. }
  46. loadDate();
  47. sendMessage(REFRESH_LIST);
  48. }
  49. }).start();
  50. }
  51. public void loadDate() {
  52. for (int i = 0; i < 100; i++) {
  53. adapter.addBook("我是challen的测试异步加" + i, "1",
  54. "http://ww1.sinaimg.cn/thumbnail/80ab1ad3gw1dx8tfjvbgdj.jpg");
  55. adapter.addBook("小美" + i, "2",
  56. "http://ww2.sinaimg.cn/thumbnail/7f9fd9a9jw1dtyrqrh4mjj.jpg");
  57. adapter.addBook("金总" + i, "3",
  58. "http://ww3.sinaimg.cn/thumbnail/9d57e8e4jw1dx6topumz5j.jpg");
  59. adapter.addBook("创意铺子" + i, "4",
  60. "http://www.pfwx.com/files/article/image/3/3237/3237s.jpg");
  61. adapter.addBook("人名日报" + i, "5",
  62. "http://ww2.sinaimg.cn/thumbnail/9263d293jw1dx8snx58s7j.jpg");
  63. adapter.addBook("名字是乱明的" + i, "6",
  64. "http://tp1.sinaimg.cn/1660452532/50/5646449168/0");
  65. adapter.addBook("帅哥即将出现" + i, "7",
  66. "http://p1.qhimg.com/t01a869bb64c7f3d8c6.png");
  67. adapter.addBook("注意了哦" + i, "8",
  68. "http://www.baidu.com/img/baidu_jgylogo3.gif");
  69. adapter.addBook("来拉" + i, "9",
  70. "http://tp4.sinaimg.cn/2190322767/50/5605436918/1");
  71. adapter.addBook("这个就是我啦" + i, "10",
  72. "http://avatar.csdn.net/E/7/2/3_jkingcl.jpg");
  73. }
  74. }
  75. private static final int REFRESH_LIST = 0x10001;
  76. public static final int SHOW_STR_TOAST = 0;
  77. public static final int SHOW_RES_TOAST = 1;
  78. private Handler pichandler = new Handler() {
  79. @Override
  80. public void handleMessage(Message msg) {
  81. if (!Thread.currentThread().isInterrupted()) {
  82. handleOtherMessage(msg.what);
  83. }
  84. }
  85. };
  86. public void sendMessage(int flag) {
  87. pichandler.sendEmptyMessage(flag);
  88. }
  89. protected void handleOtherMessage(int flag) {
  90. switch (flag) {
  91. case REFRESH_LIST:
  92. adapter.notifyDataSetChanged();
  93. default:
  94. break;
  95. }
  96. }
  97. @Override
  98. public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
  99. // TODO Auto-generated method stub
  100. }
  101. public class BookItemAdapter extends BaseAdapter {
  102. public class BookModel {
  103. public String book_id;
  104. public String out_book_url;
  105. public String author;
  106. public String book_state_s;
  107. public String leading_role;
  108. public String update_time;
  109. public String book_name;
  110. public String out_book_pic;
  111. public String sort_id;
  112. public String last_update_section_title;
  113. public String last_update_section_url;
  114. public String introduction;
  115. }
  116. private LayoutInflater mInflater;
  117. private Vector<BookModel> mModels = new Vector<BookModel>();
  118. private ListView mListView;
  119. SyncImageLoader syncImageLoader;
  120. public BookItemAdapter(Context context, ListView listView) {
  121. mInflater = LayoutInflater.from(context);
  122. syncImageLoader = new SyncImageLoader();
  123. mListView = listView;
  124. /*
  125. *
  126. * 这一句话取消掉注释的话,那么能更加的节省资源,不过体验稍微有点,
  127. * 你滑动的时候不会读取图片,当手放开后才开始度图片速度更快,你们可以试一试
  128. * */
  129. // mListView.setOnScrollListener(onScrollListener);
  130. }
  131. public void addBook(String book_name, String author, String out_book_pic) {
  132. BookModel model = new BookModel();
  133. model.book_name = book_name;
  134. model.author = author;
  135. model.out_book_pic = out_book_pic;
  136. mModels.add(model);
  137. }
  138. public void clean() {
  139. mModels.clear();
  140. }
  141. @Override
  142. public int getCount() {
  143. // TODO Auto-generated method stub
  144. return mModels.size();
  145. }
  146. @Override
  147. public Object getItem(int position) {
  148. if (position >= getCount()) {
  149. return null;
  150. }
  151. return mModels.get(position);
  152. }
  153. @Override
  154. public long getItemId(int position) {
  155. // TODO Auto-generated method stub
  156. return position;
  157. }
  158. @Override
  159. public View getView(int position, View convertView, ViewGroup parent) {
  160. if (convertView == null) {
  161. convertView = mInflater.inflate(R.layout.item_adapter,
  162. null);
  163. }
  164. BookModel model = mModels.get(position);
  165. convertView.setTag(position);
  166. ImageView iv = (ImageView) convertView.findViewById(R.id.sItemIcon);
  167. TextView sItemTitle = (TextView) convertView
  168. .findViewById(R.id.sItemTitle);
  169. TextView sItemInfo = (TextView) convertView
  170. .findViewById(R.id.sItemInfo);
  171. sItemTitle.setText(model.book_name);
  172. sItemInfo.setText(model.out_book_url);
  173. // 添加�?��背景在滑动的时�?就会显示背景而不是其他的缓存的照片,用户体验更好
  174. iv.setBackgroundResource(R.drawable.rc_item_bg);
  175. syncImageLoader.loadImage(position, model.out_book_pic,
  176. imageLoadListener, model.author);
  177. return convertView;
  178. }
  179. SyncImageLoader.OnImageLoadListener imageLoadListener = new SyncImageLoader.OnImageLoadListener() {
  180. @Override
  181. public void onImageLoad(Integer t, Drawable drawable) {
  182. // BookModel model = (BookModel) getItem(t);
  183. View view = mListView.findViewWithTag(t);
  184. if (view != null) {
  185. ImageView iv = (ImageView) view
  186. .findViewById(R.id.sItemIcon);
  187. iv.setBackgroundDrawable(drawable);
  188. }
  189. }
  190. @Override
  191. public void onError(Integer t) {
  192. BookModel model = (BookModel) getItem(t);
  193. View view = mListView.findViewWithTag(model);
  194. if (view != null) {
  195. ImageView iv = (ImageView) view
  196. .findViewById(R.id.sItemIcon);
  197. iv.setBackgroundResource(R.drawable.rc_item_bg);
  198. }
  199. }
  200. };
  201. public void loadImage() {
  202. int start = mListView.getFirstVisiblePosition();
  203. int end = mListView.getLastVisiblePosition();
  204. if (end >= getCount()) {
  205. end = getCount() - 1;
  206. }
  207. syncImageLoader.setLoadLimit(start, end);
  208. syncImageLoader.unlock();
  209. }
  210. AbsListView.OnScrollListener onScrollListener = new AbsListView.OnScrollListener() {
  211. @Override
  212. public void onScrollStateChanged(AbsListView view, int scrollState) {
  213. switch (scrollState) {
  214. case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
  215. syncImageLoader.lock();
  216. break;
  217. case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
  218. loadImage();
  219. break;
  220. case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
  221. syncImageLoader.lock();
  222. break;
  223. default:
  224. break;
  225. }
  226. }
  227. @Override
  228. public void onScroll(AbsListView view, int firstVisibleItem,
  229. int visibleItemCount, int totalItemCount) {
  230. // TODO Auto-generated method stub
  231. }
  232. };
  233. }
  234. }

其次是实现异步加载和缓存图片的功能代码loader.java

  1. package com.challen;
  2. import java.io.DataInputStream;
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.FileOutputStream;
  6. import java.io.IOException;
  7. import java.io.InputStream;
  8. import java.lang.ref.SoftReference;
  9. import java.net.URL;
  10. import java.util.HashMap;
  11. import android.graphics.drawable.Drawable;
  12. import android.os.Environment;
  13. import android.os.Handler;
  14. public class SyncImageLoader {
  15. private Object lock = new Object();
  16. private boolean mAllowLoad = true;
  17. private boolean firstLoad = true;
  18. private int mStartLoadLimit = 0;
  19. private int mStopLoadLimit = 0;
  20. final Handler handler = new Handler();
  21. private HashMap<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();
  22. public interface OnImageLoadListener {
  23. public void onImageLoad(Integer t, Drawable drawable);
  24. public void onError(Integer t);
  25. }
  26. public void setLoadLimit(int startLoadLimit,int stopLoadLimit){
  27. if(startLoadLimit > stopLoadLimit){
  28. return;
  29. }
  30. mStartLoadLimit = startLoadLimit;
  31. mStopLoadLimit = stopLoadLimit;
  32. }
  33. public void restore(){
  34. mAllowLoad = true;
  35. firstLoad = true;
  36. }
  37. public void lock(){
  38. mAllowLoad = false;
  39. firstLoad = false;
  40. }
  41. public void unlock(){
  42. mAllowLoad = true;
  43. synchronized (lock) {
  44. lock.notifyAll();
  45. }
  46. }
  47. public void loadImage(Integer t, String imageUrl,
  48. OnImageLoadListener listener,String author1) {
  49. final OnImageLoadListener mListener = listener;
  50. final String mImageUrl = imageUrl;
  51. final Integer mt = t;
  52. final String author = author1;
  53. new Thread(new Runnable() {
  54. @Override
  55. public void run() {
  56. if(!mAllowLoad){
  57. synchronized (lock) {
  58. try {
  59. lock.wait();
  60. } catch (InterruptedException e) {
  61. // TODO Auto-generated catch block
  62. e.printStackTrace();
  63. }
  64. }
  65. }
  66. if(mAllowLoad && firstLoad){
  67. loadImage(mImageUrl, mt, mListener,author);
  68. }
  69. if(mAllowLoad && mt <= mStopLoadLimit && mt >= mStartLoadLimit){
  70. loadImage(mImageUrl, mt, mListener,author);
  71. }
  72. }
  73. }).start();
  74. }
  75. private void loadImage(final String mImageUrl,final Integer mt,final OnImageLoadListener mListener,final String author){
  76. if (imageCache.containsKey(mImageUrl)) {
  77. System.out.println("drawable");
  78. SoftReference<Drawable> softReference = imageCache.get(mImageUrl);
  79. final Drawable d = softReference.get();
  80. if (d != null) {
  81. handler.post(new Runnable() {
  82. @Override
  83. public void run() {
  84. if(mAllowLoad){
  85. mListener.onImageLoad(mt, d);
  86. }
  87. }
  88. });
  89. return;
  90. }
  91. }
  92. try {
  93. final Drawable d = loadImageFromUrl(mImageUrl,author);
  94. if(d != null){
  95. imageCache.put(mImageUrl, new SoftReference<Drawable>(d));
  96. }
  97. handler.post(new Runnable() {
  98. @Override
  99. public void run() {
  100. if(mAllowLoad){
  101. mListener.onImageLoad(mt, d);
  102. }
  103. }
  104. });
  105. } catch (IOException e) {
  106. handler.post(new Runnable() {
  107. @Override
  108. public void run() {
  109. mListener.onError(mt);
  110. }
  111. });
  112. e.printStackTrace();
  113. }
  114. }
  115. public static Drawable loadImageFromUrl(String url,String author) throws IOException {
  116. //是否SD卡可用
  117. if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
  118. //检查是或有保存图片的文件夹,没有就穿件一个
  119. String FileUrl = Environment.getExternalStorageDirectory()+"/TestSyncListView/";
  120. File folder = new File(FileUrl);
  121. if(!folder.exists()){
  122. folder.mkdir();
  123. }
  124. File f = new File(FileUrl+author+".jpg");
  125. //SD卡中是否有该文件,有则直接读取返回
  126. if(f.exists()){
  127. FileInputStream fis = new FileInputStream(f);
  128. Drawable d = Drawable.createFromStream(fis, "src");
  129. return d;
  130. }
  131. //没有的话则去连接下载,并写入到SD卡中
  132. URL m = new URL(url);
  133. InputStream i = (InputStream) m.getContent();
  134. DataInputStream in = new DataInputStream(i);
  135. FileOutputStream out = new FileOutputStream(f);
  136. byte[] buffer = new byte[1024];
  137. int   byteread=0;
  138. while ((byteread = in.read(buffer)) != -1) {
  139. out.write(buffer, 0, byteread);
  140. }
  141. in.close();
  142. out.close();
  143. Drawable d = Drawable.createFromStream(i, "src");
  144. return loadImageFromUrl(url,author);
  145. }
  146. //SD卡不可用则直接加载使用
  147. else{
  148. URL m = new URL(url);
  149. InputStream i = (InputStream) m.getContent();
  150. Drawable d = Drawable.createFromStream(i, "src");
  151. return d;
  152. }
  153. }
  154. }

最后附上整个测试demo的下载地址,各位可以去下载,然后根据自己的需求加入到自己的项目中,希望可以帮助到大家,大家多多交流哦!

http://download.csdn.net/detail/jkingcl/4726519

上一篇:LeetCode 102


下一篇:室内温湿度检测系统解决方案