当前位置: 移动技术网 > IT编程>移动开发>Android > Android实现listview动态加载数据分页的两种方法

Android实现listview动态加载数据分页的两种方法

2019年07月24日  | 移动技术网IT编程  | 我要评论

照华农庄,北京 枪战,商务信息网

在android开发中,经常需要使用数据分页,比如要实现一个新闻列表的显示,或者博文列表的显示,不可能第一次加载就展示出全部,这就需要使用分页的方法来加载数据,在android中handler经常用来在耗时的工作中,它接收子线程发送的数据,并使用数据配合更新ui,asynctask是在一个线程中执行耗时操作然后把结果传给ui线程,不需要你亲自去管理线程和句柄。

一、使用handler+线程方法
1、基础知识
handler在android系统中,主要负责发送和接收消息,它的用途主要有以下两种:
(1)按照计划来处理一个消息(sendmessage(message)方法)或者执行某个runnable实例(post(runnable)方法)
(2)把其他的线程对象放入消息队列中,避免线程冲突。
消息的发送通过post(runnable), postattime(runnable, long), postdelayed(runnable, long), sendemptymessage(int),sendmessage(message), sendmessageattime(message, long)和 sendmessagedelayed(message, long) 方法完成。对于postxxx方法通过runnable对象给消息队列,并在消息队列到达后被调用。对于sendmessagexxx方法,则传递一个包含message对象,该对象可以被handler类的handlermessage(message)方法处理。
2、主要代码

public class handlerdemo extends activity implements onscrolllistener {

 private listview mlistview;
 linearlayout loadinglayout;
 private thread mthread;
 private listviewadapter adapter;

 private int startindex = 1;// 从第1条开始
 private int size = 10;// 每次下载十条数据
 private list<news> newslist;
 list<map<string, string>> data ;

 /*
 * 设置布局显示属性
 */
 private layoutparams mlayoutparams = new layoutparams(
  linearlayout.layoutparams.wrap_content,
  linearlayout.layoutparams.wrap_content);

 private layoutparams fflayoutparams = new layoutparams(
  linearlayout.layoutparams.fill_parent,
  linearlayout.layoutparams.fill_parent);

 private progressbar progressbar;

 @override
 protected void oncreate(bundle savedinstancestate) {
 // todo auto-generated method stub
 super.oncreate(savedinstancestate);
 setcontentview(r.layout.news_main);
 data=new arraylist<map<string, string>>();
 addview();
 }

 private void addview() {
 if (startindex == 1) {
  newslist = new arraylist<news>();
  newslist = getnewslist();
 }
 getdata(newslist);
 linearlayout layout = new linearlayout(this);
 layout.setorientation(linearlayout.horizontal);
 progressbar = new progressbar(this);
 layout.addview(progressbar, mlayoutparams);
 textview textview = new textview(this);
 textview.settext("加载中...");
 textview.setgravity(gravity.center_vertical);
 layout.addview(textview, fflayoutparams);
 layout.setgravity(gravity.center);
 loadinglayout = new linearlayout(this);
 loadinglayout.addview(layout, mlayoutparams);
 loadinglayout.setgravity(gravity.center);

 // 得到一个listview用来显示条目
 mlistview = (listview) findviewbyid(r.id.listview);
 mlistview.addfooterview(loadinglayout);
 adapter = new listviewadapter();
 mlistview.setadapter(adapter);
 mlistview.setonscrolllistener(this);
 mlistview.settextfilterenabled(true);
 }

 @override
 public void onscroll(abslistview view, int firstvisibleitem,
  int visibleitemcount, int totalitemcount) {
 // todo auto-generated method stub
 if (firstvisibleitem + visibleitemcount == totalitemcount) {
  if (mthread == null || !mthread.isalive()) {
  mthread = new thread() {

   @override
   public void run() {
   newslist = new arraylist<news>();
   newslist = getnewslist();
   getdata(newslist);
   message msg = new message();
   msg.what = 1;
   handler.sendmessage(msg);
   }
  };
  mthread.run();
  }
 }
 }
 
 handler handler = new handler() {

 @override
 public void handlemessage(message msg) {
  // todo auto-generated method stub
  if (msg.what == 1) {
  startindex = startindex + size;
  log.v("startindex", startindex + "");
  mlistview.removefooterview(loadinglayout);
  mthread.stop();
  adapter.count += size;
  adapter.notifydatasetchanged();
  return;
  }
 }
 };

 class listviewadapter extends baseadapter {
 int count = 10;

 @override
 public int getcount() {
  // todo auto-generated method stub
  return count;
 }

 @override
 public object getitem(int position) {
  // todo auto-generated method stub
  return position;
 }

 @override
 public long getitemid(int position) {
  // todo auto-generated method stub
  return position;
 }
 
 @override
 public view getview(int position, view convertview, viewgroup parent) {
  // todo auto-generated method stub
  convertview = layoutinflater.from(getapplicationcontext()).inflate(
   r.layout.news_item, null);
  textview textview = (textview) convertview
   .findviewbyid(r.id.textnewstitle);
  textview.settext((data.get(position)).get("title"));
  return convertview;
 }
 }

 @override
 public void onscrollstatechanged(abslistview view, int scrollstate) {
 // todo auto-generated method stub

 }

 private list<map<string, string>> getdata(list<news> list) {

 if (list == null)
  return null;
 for (news news : list) {
  map<string, string> map = new hashmap<string, string>();
  map.put("title", news.gettitle());
  data.add(map);
 }
 return data;
 }

 /*
 * 获取网络数据 注:我是访问本机的一个新闻服务,使用asp.net技术来实现的
 * 这个是项目是一个基于android的资讯播报软件
 */
 private list<news> getnewslist() {
 string path = "http://10.0.2.2/getnewslist.aspx";
 string xmlstr = "<?xml version='1.0' encoding='utf-8'?><source><categoryids>1,3,7</categoryids><startindex>"
  + startindex
  + "</startindex><detail>2</detail><count>"
  + size
  + "</count></source>";
 newsconnector newsconnector = new newsconnector();
 list<news> list = new arraylist<news>();
 list = newsconnector.getnewslist(path, xmlstr);
 return list;
 }
}

3、小结
listview使用handler+线程方式来动态加载数据的步骤如下:
1.先初始化页面(如:加载第一页数据)
2.在接收某个事件的消息之后(以上代码是onscroll事件),启动线程(线程完成下载数据,并发送消息给handler)
3.handler接收到消息后更新界面,显示数据。

二、使用asynctask方法
1、基础知识
asynctask也是android提供的一个为了不能阻塞主线程的一个类,asynctask定义了三种泛型类型params、progress和result,params启动任务执行输入参数,比如http请求的url和参数,progress后台执行任务的百分比,后台执行最终返回的结果。
asynctask的执行分为四个步骤,每一步都对应都对应一个回调方法,开发者需要实现一个或者几个方法,在任务的执行过程中,这些方法会自动调用。
onpreexecute(),在执行后台耗时操作前被调用,可以在执行此方法中做一些ui操作,比如显示一个进度条等
doinbackground(params...),这个方法在执行onpreexecute()后执行,这个方法完成耗时工作,比如下载等。
onprogressupdate(progress...),ui线程通过此方法获取任务的完成的情况,比如完成的任务的百分比。
onpostexecute(result),这个方法在耗时工作完成后被调用。ui线程调用此方法获取结果。
注意:在使用asynctask类,有几条准则需要遵守
(1)、task的实例必须在ui线程中创建
(2)、execute方法必须在ui线程中调用
(3)、不要手动调用以上四个方法
(4)、这个任务只执行一次(如果执行第二次将会抛出异常)
2、主要代码

@override
 public void onscroll(abslistview arg0, int arg1, int arg2, int arg3) {
 // todo auto-generated method stub
 if(arg1+arg2==arg3)
 {
  if(!isloading)
  {
  new myasynctask().execute(null);
  }
  else
  {
  mlistview.removefooterview(loadinglayout);
  }
 }
 }

 @override
 public void onscrollstatechanged(abslistview arg0, int arg1) {
 // todo auto-generated method stub
 
 }
 
 private class myasynctask extends asynctask<void, void, void>
 {

 @override
 protected void doinbackground(void... params) {
  // todo auto-generated method stub
  
  newslist = new arraylist<news>();
  newslist = getnewslist();
  getdata(newslist);
  return null;
  
 }

 @override
 protected void onpostexecute(void result) {
  // todo auto-generated method stub
  super.onpostexecute(result);
  adapter.count+=size;
  adapter.notifydatasetchanged();
  startindex+=size;
  isloading=false;
 }

 @override
 protected void onpreexecute() {
  // todo auto-generated method stub
  super.onpreexecute();
  isloading=true;
 }
 
 }

注:以上仅是和使用handler+线程方法不同的代码,建议下载源码:,了解详细代码
3、小结
listview使用asynctask方法动态加载数据的方法如下:
1.和handler一样初始化页面(如:加载第一页)
2.在接收某个事件的消息之后(以上代码是onscroll事件),创建一个新的异步任务,并开始执行
3.耗时工作完成后,开始更新ui 

三、总结
使用handler+线程和使用asynctask方法进行listview动态加载的比较
handler+线程方式:
在使用handler方式时,它涉及handler、thread、message、looper四个对象,在执行的流程如下:主线程启动一个thread,这个thread执行耗时操作,耗时操作完成后,生成一个message,looper读取message并传递给hander,handler接收message并更新响应的ui。因为looper在一个message处理完,才会读下一条,如果发生多个message就会形成一个消息队列,所以它对多个后台操作比较清晰,明朗。但对于单个message来讲显得代码比较多,过于复杂。
asynctask方式:
asynctask继承自object,是android提供的轻量级的异步类。并提供了一个方法来获取任务的执行进度(可以根据它来更新ui),最后会把结果返回在主线程。这个方式的比较简单,而且可以清楚的看到耗时任务执行的进度。但是对于多个异步操作同时进行,并更新ui变得比较复杂。

附件上截图

参考文章:android listview动态加载列表项实现代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网