我们在项目开发过程中,最常用的控件就是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