您的位置:首页 > 其它

ListView分页加载数据

2016-06-16 08:04 330 查看

ListView分页加载数据

ListView分页加载 在Android中是一个经常用到的技术,当我们需要加载大量的数据到列表显示时,假如一次性把所有数据加载完毕,可能会导致整个ListView列表卡顿,给用户的体验也非常不好。因而,我们可以将数据分为多次加载,每次加载其中的一部分,用户有需求的时候再加载其他部分,这样的设计会更加友好。

ListView分页原理

在日常开发中,我们可能会遇到以下两种情况:

服务器支持分页请求,简单地说,比如,我们总共要请求100条数据,服务器支持我们每次请求N条数据,我们可以分100 / N 次请求完成,并且这些数据有一定的顺序,我们想请求第几页的数据就可以请求第几页的数据(这种情况下,我们可以实现真正的分页加载数据)。

服务器不支持分布请求,我们没办法请求指定页的数据,只能一次性请求所有数据(这种情况下,我们只能自己处理,每次加载相应数目数据到ListView中)。

那么ListView分页原理就是,我们不一次性加载所有的数据,每次加载N条,然后我们监听ListView的滚动事件,当ListView滚动到最底部时,判定当前是否已加载完所有数据,如果未加载完毕,请求新一页的数据,直至所有的数据加载完成。

Demo实现

一般情况下,我们需要请求服务器的数据,但是这里我们只是要达到ListView分页加载的效果,我们自己模拟数据加载过程。

首先是我们的主页面MainActivity,其对应的页面文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.hotzhi.listviewtest.MainActivity">

<ListView
android:id="@+id/lv_data"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fastScrollEnabled="false"
android:smoothScrollbar="true"
android:cacheColorHint="#00000000"
android:divider="#ffcccccc"
android:dividerHeight="0.2dp" />

</RelativeLayout>


这里没啥好介绍的,就只是一个ListView。接下来是,我们将ListView拖动到底部时,如果要加载新的数据,那么我们可以添加一个footerView,以更好的提示用户,下面是其布局文件,foot_view.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff" >

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="true"
android:gravity="center|center_vertical"
android:orientation="horizontal"
android:paddingBottom="15dp"
android:paddingTop="15dp" >

<ProgressBar
android:id="@+id/progressBar_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center"
style="?android:attr/progressBarStyleSmall"
android:paddingBottom="2dp"
android:paddingTop="2dp" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:gravity="center"
android:text="加载更多中……"
android:textSize="13sp" />
</LinearLayout>

</FrameLayout>


也非常简单,就一个加载框,然后一个提示文本。

下面就是我们的具体实现了,MainActivity.java

package com.hotzhi.listviewtest;

import android.os.Bundle;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

/** 列表翻页每页加载数目 */
private static final int ONE_PAGE_ITEM_COUNT = 20;
// 由于这里是测试数据,我们自己控制所有数据请求的结束位置,也就是页数达到MAX_PAGE无法再次请求数据。
/** 最大页数(测试) */
private static final int MAX_PAGE = 8;

private List<String> lstData = new ArrayList<>();
private ArrayAdapter<String> mAdapter;
private ListView lvData;

/** 当前页码 */
public int iCurPageIndex = 0;
/** 列表第一项 */
private int firstItem;
/** 列表可见项 */
private int visibleItem;
/** 列表可见项 */
private int totalItem;
/** 是否可以上拉 */
private boolean canUpPull = true;
/** 是否正在加载 */
private boolean isLoading = false;
/** 页脚布局 */
private FrameLayout mFooterView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

findViews();
setListeners();
initData();

}

private void findViews() {
lvData = (ListView) findViewById(R.id.lv_data);
mFooterView = (FrameLayout) LayoutInflater.from(this).inflate(R.layout.foot_view, null);
}

private void setListeners() {
lvData.setOnScrollListener(onScrollListener);
}

private void initData() {
requestData();
}

/**
* ListView滚动监听器
*/
private AbsListView.OnScrollListener onScrollListener = new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {

if (firstItem + visibleItem == totalItem) {

// 当前处于不可上拉加载状态,不可继续请求数据
if(!canUpPull) {
return ;
}

// 数据正在加载,不可继续请求
if(isLoading) {
return ;
}

lvData.addFooterView(mFooterView);
lvData.setSelection(lvData.getBottom());
isLoading = true;
iCurPageIndex++;
requestData();
}
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
firstItem = firstVisibleItem;
visibleItem = visibleItemCount;
totalItem = totalItemCount;
}
};

/**
* 请求加载更多数据
* 如,请求服务器数据
*/
private void requestData() {

// 这里我们休眠3秒钟,相当于3秒钟后数据才加载完毕
// 当然我们在实际项目中可能不需要休眠处理,直接请求数据等待数据返回即可。
new Thread() {
public void run() {
try {
Thread.sleep(3000);
// 主线程中加载数据
handler.sendEmptyMessage(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();

}

private android.os.Handler handler = new android.os.Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);

// 加载数据
// 加载第iCurPageIndex页数据
for(int i = iCurPageIndex * ONE_PAGE_ITEM_COUNT; i < (iCurPageIndex + 1) * ONE_PAGE_ITEM_COUNT; i++) {
lstData.add("第" + i + "条数据");
}

// 数据加载完毕设置相应标志
isLoading = false;
canUpPull = true;
lvData.removeFooterView(mFooterView);

// 这里我们通过判断加载页位置与最大可加载页比较判断,是否已加载完所有数据
if(iCurPageIndex >= MAX_PAGE) {
canUpPull = false;
if(iCurPageIndex > 0) {
Toast.makeText(MainActivity.this, "已到达最后一页!", Toast.LENGTH_SHORT).show();
}
}

if(mAdapter == null) {
mAdapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, android.R.id.text1, lstData);
lvData.setAdapter(mAdapter);
} else {
mAdapter.notifyDataSetChanged();
}
}
};
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  listview 分页