我们在项目开发过程中,最常用的控件就是ListView,常用的场景也就是以列表的方式显示数据,当我们的应用联网的时候,可以下拉刷新获取更多的数据;
当没有更多的数据的时候,会提醒我们没有更多数据。
这里我简单总结了一下分页加载数据,希望大家提出宝贵的意见,或者有什么更好的方法与我一起分享学习:
首先看一下效果图:
服务端代码:
web工程结构图(记得导入需要的jar包):
Student.java
package com.xbmu.bean;
import java.io.Serializable;
import java.util.Date;
public class Student implements Serializable {
private String stuicon;
private String username;
private Date birthday;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String stuicon, String username, Date birthday) {
super();
this.stuicon = stuicon;
this.username = username;
this.birthday = birthday;
}
public String getStuicon() {
return stuicon;
}
public void setStuIcon(String stuicon) {
this.stuicon = stuicon;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Student [stuIcon=" + stuicon + ", username=" + username
+ ", birthday=" + birthday + "]";
}
}
StuDataSource.java
package com.xbmu.db;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.xbmu.bean.Student;
/**
* 模拟数据库,在这里添加100条学生记录
* @author bitaotao
*
*/
public class StuDataSource {
private List<Student> list = new ArrayList<Student>();
public List<Student> getDataSource() {
for (int i = 0; i < 100; i++) {
Student student = new Student("***", "zhangsan"+i,new Date());
list.add(student);
}
return list;
}
}
DevidePage.java
package com.xbmu.utils;
/**
* 分页工具
*
* @author bitaotao
*
*/
public class DevidePage {
private int pageSize;// 每页显示的条数
private int recordCount;// 记录的总条数
private int currentPage;// 当前页
private int pageCount;// 总页数
/**
*
* @param pageSize 每页显示的条数
* @param recordCount 总记录条数
* @param currentPage 当前页数
*/
public DevidePage(int pageSize, int recordCount, int currentPage) {
this.pageSize = pageSize;
this.recordCount = recordCount;
this.setCurrentPage(currentPage);
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getRecordCount() {
return recordCount;
}
public void setRecordCount(int recordCount) {
this.recordCount = recordCount;
}
/**
* 获得总页数
*/
public int getPageCount() {
pageCount = recordCount / pageSize;
int mod = recordCount % pageSize;
if (mod != 0) {
pageCount++;
}
return pageCount == 0 ? 1 : pageCount;
}
public void setPageCount(int pageCount) {
this.pageCount = pageCount;
}
public int getCurrentPage() {
return currentPage;
}
/**
* 设置定位在当前页
*/
private void setCurrentPage(int currentPage) {
int activePage = currentPage <= 0 ? 1 : currentPage;
activePage = activePage > getPageCount() ? getPageCount() : activePage;
this.currentPage = activePage;
}
public int getFromIndex() {
return (currentPage - 1) * pageSize;
}
public int getToIndex() {
return Math.min(recordCount, currentPage * pageSize);
}
}
JsonDateValueProcessor.java
package com.xbmu.utils;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor;
public class JsonDateValueProcessor implements JsonValueProcessor {
private String pattern = "yyyy-MM-dd";
public Object processArrayValue(Object value, JsonConfig config) {
return process(value);
}
public Object processObjectValue(String key, Object value, JsonConfig config) {
return process(value);
}
private Object process(Object value){
if(value instanceof Date){
SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.UK);
return sdf.format(value);
}
return value == null ? "" : value.toString();
}
}
StuServlet.java
package com.xbmu.web.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import com.xbmu.bean.Student;
import com.xbmu.db.StuDataSource;
import com.xbmu.utils.DevidePage;
import com.xbmu.utils.JsonDateValueProcessor;
public class StuServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//解决乱码问题
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
StuDataSource dataSource = new StuDataSource();
/**
* 获取StuDataSource类中的数据
*/
List<Student> list = dataSource.getDataSource();
String pageNo = request.getParameter("pageNo");
int currentPage = 1;// 当前页是第一页
if (pageNo != null) {
currentPage = Integer.parseInt(pageNo);
}
/**
* 分页:每页有25条数据,因为有100条,所以总共有4页。
*/
DevidePage pUtil = new DevidePage(25, list.size(), currentPage);
int start = pUtil.getFromIndex();
int end = pUtil.getToIndex();
//总页数
int pageCount = pUtil.getPageCount();
//分页数据,存储在集合中了
List<Student> subList = list.subList(start, end);
//json配置对象
JsonConfig jsonConfig = new JsonConfig();
//注册json值处理器
jsonConfig.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor());
//将集合转换成json对象
Map<String, Object> map = new HashMap<String,Object>();
map.put("pageCount", pageCount);//将总页数存储到Map集合中
map.put("sublist", subList);//将分页数据存储到集合中
//将map集合中的数据转换成json格式的字符串
JSONObject jsonObject = new JSONObject();
jsonObject = jsonObject.fromObject(map,jsonConfig);
PrintWriter writer = response.getWriter();
writer.println(jsonObject);
writer.flush();
writer.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
启动tomcat,将web程序部署到服务器上。访问地址:http://10.6.159.37:8080/TestServer/stuServlet?pageNo=1
运行结果:
客户端代码:
MainActivity.java
package com.xbmu;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.xbmu.bean.Student;
import com.xbmu.http.HttpUtil;
import com.xbmu.parser.ParserNetData;
public class MainActivity extends Activity {
private String BASE_URL = "http://10.6.159.37:8080/TestServer/stuServlet?pageNo=";
private ListView listView;
private MyAdapter adapter;
private boolean is_divPage;// 是否进行分页操作
private List<Student> oneTotal = new ArrayList<Student>();// 用来存放一页数据
private List<Student> total = new ArrayList<Student>();// 用来存放获取的所有数据
private ProgressDialog dialog;// 进度对话框对象
private static int pageNo = 1;// 设置pageNo的初始化值为1,即默认获取的是第一页的数据。
private static int pageCount;//总页数,从服务端获取过来
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
dialog = new ProgressDialog(MainActivity.this);
dialog.setTitle("警告");
dialog.setMessage("正在加载信息...");
adapter = new MyAdapter();
/**
* 用来获取数据...
*/
new MyTask().execute(BASE_URL + pageNo);
listView.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
/**
* 当分页操作is_divPage为true时、滑动停止时、且pageNo<=pageCount(这里因为服务端有pageCount页数据)时,加载更多数据。
*/
if (is_divPage && scrollState == OnScrollListener.SCROLL_STATE_IDLE && pageNo <= pageCount) {
Toast.makeText(MainActivity.this, "正在获取更多数据...",
Toast.LENGTH_SHORT).show();
new MyTask().execute(BASE_URL + pageNo);
} else if (pageNo > pageCount) {
/**
* 如果pageNo>pageCount则表示,服务端没有更多的数据可供加载了。
*/
Toast.makeText(MainActivity.this, "没有更多数据啦...",
Toast.LENGTH_SHORT).show();
}
}
/**
* 当第一个可见的item(firstVisibleItem)+可见的item的个数(visibleItemCount)=
* 所有的item总数的时候, is_divPage变为TRUE,这个时候才会加载数据。
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
is_divPage = (firstVisibleItem + visibleItemCount == totalItemCount);
}
});
}
/**
* 覆写activity的销毁方法,在销毁activity之前将初始也pageNo设置为默认值1
* 如果没有覆写该方法并没有恢复pageNo的默认值。那么等你退出应用后,重新点击应用图标进去
* 会获取不到任何值(因为第一次加载数据的时候,pageNo已经快速增加到pageNo的最大值)
* 这里有什么问题或者不同的理解,请各位朋友指出。
* */
@Override
protected void onDestroy() {
pageNo = 1;
super.onDestroy();
}
/**
* MyTask继承线程池AsyncTask用来网络数据请求、json解析、数据更新等操作。
* AsyncTask<Params, Progress, Result>
* Params:在执行AsyncTask时需要传入的参数,可用于在后台任务中使用
* Progress:后台人物执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位
* Result:当人物执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型
*/
class MyTask extends AsyncTask<String, Void, String> {
/**
* 数据请求前显示dialog。
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
dialog.show();
}
/**
* 在doInBackground方法中,做一些诸如网络请求等耗时操作。
*/
@Override
protected String doInBackground(String... params) {
return HttpUtil.RequestData(BASE_URL + pageNo);
}
/**
* 在该方法中,主要进行一些数据的处理,更新。
*/
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (result != null) {
// 如果获取的result数据不为空,那么对其进行JSON解析。并显示在手机屏幕上。
oneTotal.clear();
List<Student> list = ParserNetData.parseFromJson(oneTotal,result);
pageCount = (Integer) ParserNetData.getPageCount(result);
total.addAll(list);
adapter.bindData(total);
/**
* 当pageNo等于1的时候才会setAdapter,以后不会再设置,直接notifyDataSetChanged,
* 进行数据更新 ,这样可避免每次加载更多数据的时候,都会重新回到第一页。
*/
if (pageNo == 1) {
listView.setAdapter(adapter);
}
adapter.notifyDataSetChanged();
pageNo++;
System.out.println("pageNo="+pageNo);
} else if (result == null) {
Toast.makeText(MainActivity.this, "请求数据失败...",
Toast.LENGTH_LONG).show();
}
dialog.dismiss();
}
}
/**
* ListView的适配器
*/
class MyAdapter extends BaseAdapter {
List<Student> list;
/**
* bindData用来传递数据给适配器。
*
* @param list
*/
public void bindData(List<Student> list) {
this.list = list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = View.inflate(MainActivity.this, R.layout.list_item,
null);
ImageView iv_icon = (ImageView) view.findViewById(R.id.iv_icon);
TextView tv_name = (TextView) view.findViewById(R.id.tv_name);
TextView tv_date = (TextView) view.findViewById(R.id.tv_date);
iv_icon.setBackgroundResource(R.drawable.notice);
tv_name.setText(list.get(position).getUsername());
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date birthdayDate = list.get(position).getBirthday();
String birthday = dateFormat.format(birthdayDate);
tv_date.setText(birthday);
return view;
}
}
}
Student.java和服务端的bean一样,这里不再写了。
HttpUtil.java
package com.xbmu.http;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
public class HttpUtil {
/**
* 分页请求网络数据
* @param pageNo 请求的页码
* @return 返回json格式的数据
*/
public static String RequestData(String netUrl) {
HttpGet get = new HttpGet(netUrl);
HttpClient client = new DefaultHttpClient();
StringBuilder builder = null;
try {
HttpResponse response = client.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
InputStream inputStream = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(
new InputStreamReader(inputStream));
builder = new StringBuilder();
String s = null;
for (s = reader.readLine(); s != null; s = reader.readLine()) {
builder.append(s);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return builder.toString();
}
}
ParserNetData.java
package com.xbmu.parser;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.xbmu.bean.Student;
public class ParserNetData {
/**
* 解析json字符串
* @param oneTotal 该集合用来存放一页数据
* @param result 请求网络,服务器返回的字符串(json格式)
* @return
*/
public static List<Student> parseFromJson(List<Student> oneTotal,String result) {
JSONArray array = null;
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(result);
String sublist = jsonObject.getString("sublist");
array = new JSONArray(sublist);
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
Student stuInfo = new Student();
stuInfo.setStuIcon(obj.getString("stuicon"));
stuInfo.setUsername(obj.getString("username"));
String dateStr = obj.getString("birthday");
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date birthday = dateFormat.parse(dateStr);
stuInfo.setBirthday(birthday);
oneTotal.add(stuInfo);
}
return oneTotal;
} catch (Exception e) {
return null;
}
}
/**
* 获得总页数
* @param result json字符串
* @return 返回json封装的总页数
*/
public static Object getPageCount(String result){
try {
JSONObject jsonObject = new JSONObject(result);
Object pageCount = jsonObject.get("pageCount");
System.out.println("总页数"+pageCount);
return pageCount;
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
}
客户端与服务端所有源码下载地址:
http://download.csdn.net/detail/btt2013/9323905