关于ListView上拉刷新的需求很多,实现方式也多种多样。
一般是简单的通过一个page变量来控制当前请求的页数,然后上拉的时候就发送请求。
实现出来后,经过测试哥的折腾,发现有诸多细节没有处理好,比如会出现重复数据,反复的上拉导致多次请求等bug。
后来就决定单独写一个工具类,方便以后需要直接使用。
1 public class ListViewScrollHelper<T> { 2 private static final String TAG = "ListViewScrollHelper"; 3 private static final int LIST_PAGE_SIZE = 15; 4 5 private NextPage nextPage; 6 private InitAdapter initAdapter; 7 8 private int pageIndex = -1; 9 private int totalPage; 10 11 private ListView lv_goodsList; 12 private BaseAdapter goodsAdapter; 13 private List<T> goodsList = new ArrayList<>(); 14 private Semaphore semaphore = new Semaphore(0); 15 16 public ListViewScrollHelper(ListView lv_goodsList, InitAdapter initAdapter, NextPage nextPage) { 17 this.initAdapter = initAdapter; 18 this.lv_goodsList = lv_goodsList; 19 this.nextPage = nextPage; 20 initView(); 21 } 22 23 private void initView() { 24 goodsAdapter = initAdapter.initAdapter(goodsList); 25 lv_goodsList.setAdapter(goodsAdapter); 26 lv_goodsList.setOnScrollListener(new AbsListView.OnScrollListener() { 27 @Override 28 public void onScrollStateChanged(AbsListView view, int scrollState) { 29 } 30 31 @Override 32 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 33 34 // 判断是否到底部了 35 if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) { 36 Log.d(TAG, String.valueOf(pageIndex)); 37 if (hasNextPage() && canRequestNextPage()) { 38 pageIndex++; 39 if (nextPage != null) 40 nextPage.next(); 41 } else { 42 Log.d(TAG, "列表已经到底部!"); 43 } 44 } 45 } 46 }); 47 } 48 49 /** 50 * 此函数将会作为分页刷新数据的主函数 51 * 内部将会实现 根据当前页数判断是否重置数据 或者 继续下一页 52 * 如果重置数据,初始化起始页需要使用函数 resetPageIndex() 53 * 54 * @param list 55 * @param totalSize 56 */ 57 public void refreshPage(List list, int totalSize) { 58 if (pageIndex < 0) { 59 initData(list, totalSize); 60 } else { 61 freshList(list); 62 } 63 } 64 65 /** 66 * 如果有多处控制一个listview数据内容(比如:分类,搜索都能控制商品列表展示) 67 * ,此时可以使用此函数设置分页信息 68 * 69 * @param list 70 * @param totalSize 71 */ 72 public void initData(List list, int totalSize) { 73 pageIndex = 0; 74 goodsList.clear(); 75 76 if (totalSize > LIST_PAGE_SIZE) { 77 totalPage = totalSize / LIST_PAGE_SIZE; 78 if (totalSize % LIST_PAGE_SIZE >= 1) 79 totalPage++; 80 Log.d("wbl", "totalPage:" + totalPage); 81 } else { 82 totalPage = 1; 83 } 84 85 freshList(list); 86 } 87 88 /** 89 * 设置下一面的数据 90 * 91 * @param list 92 * @param type (此字段废弃) 93 */ 94 public void nextPage(List list, int type) { 95 freshList(list); 96 } 97 98 /** 99 * 当请求失败时,恢复上到一页 100 */ 101 public void restoreLastPage() { 102 if (!canRequestNextPage()) { 103 if (pageIndex > 0) pageIndex--; 104 } 105 semaphore.release(); 106 } 107 108 private boolean hasNextPage() { 109 return pageIndex < totalPage - 1; 110 } 111 112 public int getPageIndex() { 113 return pageIndex < 0 ? 0 : pageIndex; 114 } 115 116 public int getPageIndex(boolean hasCategoryChange) { 117 if (hasCategoryChange) 118 pageIndex = 0; 119 return getPageIndex(); 120 } 121 122 /** 123 * 重置分页参数 124 */ 125 public void resetPageIndex() { 126 pageIndex = -1; 127 totalPage = 0; 128 } 129 130 public void setEmptyView(View view) { 131 lv_goodsList.setEmptyView(view); 132 } 133 134 /** 135 * @param list 传入要显示的list 136 */ 137 private void freshList(List list) { 138 if (list != null && list.size() > 0) { 139 goodsList.addAll(list); 140 } 141 goodsAdapter.notifyDataSetChanged(); 142 semaphore.release(); 143 } 144 145 private boolean canRequestNextPage() { 146 return semaphore.tryAcquire(); 147 } 148 149 public List<T> getGoodsList() { 150 return goodsList; 151 } 152 153 public interface NextPage { 154 void next(); 155 } 156 157 public interface InitAdapter<T> { 158 BaseAdapter initAdapter(List<T> list); 159 } 160 }
详细使用可以参考这个项目