为什么需要分批加载呢,一般我们在浏览数据的时候,往往要浏览的数据是很多的,例如你上淘宝买东西,一搜索可能会有好几万条结果,但是这些数据如果一下子全部加载出来,先不说你手机内存是否吃的消,假如你是流量上网,那么你的流量会瞬间消耗多少呢,况且一句手机的网速,需要加载多久也不久不用我多说了把。
因此就需要分批加载,一般来说每次加载20条数据即可。
既然是分批加载,那么肯定得有加载数据的逻辑,根据封装的思想,最好能够传入起始加载位置和加载的数量就能够返回数据的集合:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
public List<BlackNumInfo> queryPartBlackNum(int maxNum,int startIndex){ List<BlackNumInfo> infoList = new ArrayList<>(); SQLiteDatabase database = blackNumOpenHelper.getReadableDatabase(); Cursor cursor = database.rawQuery("select blackNum,mode from info order by _id desc " + "limit ? offset ?", new String[]{maxNum + "", startIndex + ""});
while (cursor.moveToNext()) { String num = cursor.getString(0); int mode = cursor.getInt(1); infoList.add(new BlackNumInfo(num, mode)); } cursor.close(); database.close(); return infoList; }
|
有了加载部分数据的逻辑,我们还需要判断加载数据的时机,仅在需要的时候再加载下一批数据。因为我们的数据是用 ListView 来显示的,那么就需要从 ListView 的状态入手。我们可以认为,当用户滑到 ListView 最底部的时候,她还想继续浏览,这个时候我们就可以放心地加载下一批数据。
因此,加载的时机就是当 ListView 窗口显示的数据条目是其对应的 adapter 的最后一条数据,也就是用户滑到了最底部的时候,就可以加载数据了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
private static final int MAXNUM = 20;
private int startIndex=0;
blackList.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) { if (blackList.getLastVisiblePosition() == list.size() - 1) { startIndex += MAXNUM; fillData(); } } }
@Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
} });
|
接下来要做什么呢,时机到了,新的数据也查到了,那么就要把数据更新到 ListView 中。在这里需要注意一些小细节:
- 当 ListView 中不存在数据和已经存在数据的情况;
- ListView 的 adapter 为空和不为空的情况;
为什么要注意这两点呢,首先一开始的时候,我们也是要采用分批加载数据的方法才加载第一批数据的。其次如果 ListView 中已经存在数据,那么就不能简单的用新查询到的数据直接替换原来的 list 数据集合,否则原先的数据就会消失,而只剩下新查询到的数据,这可不是我们的本意;最后还得对 adapter 进行判断,如果 adapter 不为空,那么就得采用通知更新的方法,而不能直接为 list 集合设置新的 adapter,否则每次加载完数据,ListView都会跳转到列表开始的位置,也就是第一条数据。
以下是具体的逻辑,其中用到了一个简单的异步加载框架:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| private void fillData() { new MyAsycTask() {
@Override public void preTask() { callLoading.setVisibility(View.VISIBLE); }
@Override public void doInBack() { if (list == null) { list = blackNumDao.queryPartBlackNum(MAXNUM, startIndex); }else { list.addAll(blackNumDao.queryPartBlackNum(MAXNUM, startIndex)); } }
@Override public void postTask() { if (myAdapter == null) { myAdapter = new MyAdapter(); blackList.setAdapter(myAdapter); } else { myAdapter.notifyDataSetChanged(); } callLoading.setVisibility(View.INVISIBLE); } }.execute(); }
|
至此,一个简单但却完整的分批加载框架就完成了。
完整的源码参见BlackNumDao.java和CallSafeActivity.java