前言:
在开发的过程中,有时候我们需要从网络解析一些数据,比如最近的一些新闻,我们需要把这些数据用ListView显示出来。
因为是解析一个网络数据源,这样将会一下子将所有的数据解析出来,当数据源数据过大时,就可能会造成解析时间过长,占用内存过大等问题。
这时候想到用分页列表来显示这些数据,即每次只显示一个屏幕所能容纳条数的列表项数据,当用户手指向下拉动的时候,才再加载一个屏幕所能容纳的条数的数据,这样就解决了上述问题。
---------------------------------------------------------------------------------------------------------------------------------
思路:
先来看一个数据源地址,内容为某一个城市待出售房屋信息
1 http://ikft.house.qq.com/index.php?guid=866500021200250&devua=appkft_1080_1920_XiaomiMI4LTE_1.8.3_Android19&order=0&searchtype=normal&devid=866500021200250&appname=QQHouse&mod=appkft&act=searchhouse&channel=71&page=1&rn=20&cityid=1
该地址红色部分代表页数,rn=20代表一页有20条相应数据
通过www.bejson.com网站解析该网址相应的JSON数据为XML格式
1 { 2 "retcode": 0, 3 "retmsg": "成功", 4 "total": "817", 5 "page": 1, 6 "rn": 20, 7 "data": [ 8 { 9 "fid": "122591", 10 "fcover": "http://p0.qpic.cn/estate/0/cbcef0b36d585650ec602ebe0ca56a18.jpg/180", 11 "fname": "鸿坤·理想湾", 12 "faddress": "涿州东高铁新城涿州东站西侧300米", 13 "fregion": "大北京", 14 "fpricedisplaystr": "7200元/平米", 15 "faroundhighprice": 7500, 16 "faroundlowprice": 6500, 17 "groupbuynum": 3587, 18 "lng": "116.052084096376", 19 "lat": "39.4636526249295", 20 "fsellstatus": "1", 21 "istencentdiscount": 0, 22 "bookmark": [ 23 { 24 "tag": "看房团", 25 "type": 2 26 }, 27 { 28 "tag": "低总价", 29 "type": 3 30 }, 31 { 32 "tag": "品牌开发商", 33 "type": 3 34 } 35 ], 36 "price_pre": "均价", 37 "price_value": "7200", 38 "price_unit": "元/平米", 39 "panoid": "", 40 "heading": "", 41 "pitch": "", 42 "has_agent": 1, 43 "hui": 1 44 }, 45
也就是说,当我们解析这个网址的数据时,会有20条数据,当把网址红色部分page=1 --->page=2 时,又将显示20条数据
怎么实现分页列表一次显示20条数据呢?
从数据源网址可以看出一个我们只要把page依次加一,便可以依次加载对应网址数据源了
也就是说,只要把每次加载的数据添加到适配器中,便可以实现分页列表每页每次加载固定个数个数据条
------------------------------------------------------------------------------------------------------------------------------------------------------------
代码:
1、解析房屋信息,我们这里先只获得房屋名字信息放到ListView中
先建一个房屋实体类
1 package com.example.listview; 2 3 public class Home { 4 private String name; 5 6 public Home() { 7 super(); 8 // TODO Auto-generated constructor stub 9 } 10 11 public Home(String name) { 12 super(); 13 this.name = name; 14 } 15 16 public String getName() { 17 return name; 18 } 19 20 public void setName(String name) { 21 this.name = name; 22 } 23 24 @Override 25 public String toString() { 26 return name; 27 } 28 29 }
2、工具类(http获取数据,json数据解析)
1 package com.example.listview; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.net.HttpURLConnection; 7 import java.net.MalformedURLException; 8 import java.net.URL; 9 10 public class HttpUtil { 11 //将指定路径上的数据转换为字节数组形式返回 12 public static byte[] getByteJsonString(String path) throws IOException 13 { 14 URL url = new URL(path); 15 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 16 conn.setRequestMethod("GET"); //Get的连接方式 17 conn.setConnectTimeout(5000); 18 conn.setDoInput(true); 19 if(conn.getResponseCode()==200)// 响应码等于200表示连接成功 20 { 21 InputStream in = conn.getInputStream(); 22 return getByteString(in); 23 } 24 return null; 25 26 } 27 28 public static byte[] getByteString(InputStream in) throws IOException 29 { 30 //内存流获取数据 31 ByteArrayOutputStream out = new ByteArrayOutputStream(); 32 int len = 0; 33 byte[] b = new byte[1024]; 34 while((len = in.read(b))!=-1) 35 { 36 //注意不要写成out.write(b); 否则若字节数据长度大于实际数据长度,后面部分乱码,导致后面json解析出错 37 out.write(b,0,len); 38 } 39 40 return out.toByteArray(); 41 } 42 43 }
1 package com.example.listview; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import org.json.JSONArray; 7 import org.json.JSONException; 8 import org.json.JSONObject; 9 10 11 public class JsonString { 12 public static List getJsonResult(String json) throws JSONException 13 { 14 //JSON解析 ,解析某一城市下所有房屋的名字 15 List<Home> list = new ArrayList<Home>(); 16 JSONObject obj = new JSONObject(json); 17 JSONArray arr = obj.getJSONArray("data"); 18 Home home = null; 19 for(int i=0;i<arr.length();i++) 20 { 21 22 JSONObject data = arr.getJSONObject(i); 23 home = new Home(); 24 25 26 String fname =data.getString("fname"); 27 home.setName(fname); 28 list.add(home); 29 } 30 return list; 31 32 33 } 34 }
3、ListView的自定义适配器类
1 package com.example.listview; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import android.content.Context; 7 import android.view.LayoutInflater; 8 import android.view.View; 9 import android.view.ViewGroup; 10 import android.widget.BaseAdapter; 11 import android.widget.TextView; 12 13 public class MyAdapter extends BaseAdapter{ 14 15 private Context context; 16 private List<Home> list; 17 18 public MyAdapter(Context context) 19 { 20 this.context = context; 21 list = new ArrayList<Home>(); 22 } 23 //关键点! 24 //将底部下拉刷新出来的数据(新解析出来的固定条数数据)添加到当前适配器中 25 public void addData(List lists){ 26 list.addAll(lists); 27 } 28 @Override 29 public int getCount() { 30 // TODO Auto-generated method stub 31 int count = 0; 32 if(list!=null) 33 return list.size(); 34 return count; 35 } 36 37 @Override 38 public Object getItem(int position) { 39 // TODO Auto-generated method stub 40 return list.get(position); 41 } 42 43 @Override 44 public long getItemId(int position) { 45 // TODO Auto-generated method stub 46 return position; 47 } 48 49 @Override 50 public View getView(int position, View convertView, ViewGroup parent) { 51 // TODO Auto-generated method stub 52 View view = null; 53 if(convertView!=null) 54 { 55 view = convertView; 56 } 57 else 58 { 59 view = LayoutInflater.from(context).inflate(R.layout.layout_item,parent, false); 60 } 61 62 ViewHolder holder = (ViewHolder) view.getTag(); 63 if(holder==null) 64 { 65 holder = new ViewHolder(); 66 holder.textview = (TextView) view.findViewById(R.id.id_textview); 67 view.setTag(holder); 68 } 69 holder.textview.setText(list.get(position).getName()); 70 return view; 71 } 72 73 class ViewHolder 74 { 75 TextView textview; 76 } 77 78 }
4、异步任务获得数据
1 package com.example.listview; 2 3 import java.io.IOException; 4 import java.io.UnsupportedEncodingException; 5 import java.util.ArrayList; 6 import java.util.List; 7 8 import org.json.JSONException; 9 10 import android.os.AsyncTask; 11 12 public class AsyncTaskHome extends AsyncTask<String, Void, List>{ 13 14 private MyAdapter myadapter; 15 private List<Home> list ; 16 //将适配器作为参数传进来 17 public AsyncTaskHome(MyAdapter myadapter) 18 { 19 this.myadapter = myadapter; 20 } 21 @Override 22 protected List doInBackground(String... params) { 23 // TODO Auto-generated method stub 24 if(params[0]!=null) 25 { 26 try { 27 String json = new String(HttpUtil.getByteJsonString(params[0]),"utf-8"); 28 list = JsonString.getJsonResult(json); 29 } catch (UnsupportedEncodingException e) { 30 // TODO Auto-generated catch block 31 e.printStackTrace(); 32 } catch (IOException e) { 33 // TODO Auto-generated catch block 34 e.printStackTrace(); 35 } catch (JSONException e) { 36 // TODO Auto-generated catch block 37 e.printStackTrace(); 38 } 39 } 40 41 return list; 42 } 43 44 @Override 45 protected void onPostExecute(List result) { 46 // TODO Auto-generated method stub 47 super.onPostExecute(result); 48 //将解析除的数据添加放入到当前适配器中 49 myadapter.addData(result); 50 //刷新适配器 51 myadapter.notifyDataSetChanged(); 52 53 54 } 55 56 }
5、主Activity
1 package com.example.listview; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.widget.AbsListView; 6 import android.widget.AbsListView.OnScrollListener; 7 import android.widget.ListView; 8 import android.widget.Toast; 9 10 public class MainActivity extends Activity { 11 12 private ListView listview ; 13 private boolean isEnd; //判断列表是否滑动到底部 14 private int page = 1;//显示第几页数据 15 @Override 16 protected void onCreate(Bundle savedInstanceState) { 17 super.onCreate(savedInstanceState); 18 setContentView(R.layout.activity_main); 19 20 listview = (ListView) findViewById(R.id.listview); 21 //创建一个自定义适配器对象 22 final MyAdapter adapter = new MyAdapter(this); 23 //将该适配器作为listView的数据源 24 listview.setAdapter(adapter); 25 //启动异步任务,先解析第一个页面的数据 26 new AsyncTaskHome(adapter).execute("http://ikft.house.qq.com/index.php?guid=866500021200250&devua=appkft_1080_1920_XiaomiMI4LTE_1.8.3_Android19&order=0&searchtype=normal&devid=866500021200250&appname=QQHouse&mod=appkft&act=searchhouse&channel=71&page=1&rn=20&cityid=1"); 27 28 listview.setOnScrollListener(new OnScrollListener() { 29 30 @Override 31 public void onScrollStateChanged(AbsListView view, int scrollState) { 32 // TODO Auto-generated method stub 33 //如果滑動到末尾並且手指離開了界面,則加載新的數據源添加到適配器中 34 if(isEnd && scrollState==OnScrollListener.SCROLL_STATE_IDLE) 35 { 36 Toast.makeText(MainActivity.this, "努力加载中---", 1).show(); 37 38 //加载一个新的数据源,包含新的20条数据 39 String path = "http://ikft.house.qq.com/index.php?guid=866500021200250&devua=appkft_1080_1920_XiaomiMI4LTE_1.8.3_Android19&order=0&searchtype=normal&devid=866500021200250&appname=QQHouse&mod=appkft&act=searchhouse&channel=71&page="+(++page)+"&rn=20&cityid=1"; 40 //执行异步任务,将当前的自定义适配器传进去,将解析的新的数据添加到当前视频日期中 41 new AsyncTaskHome(adapter).execute(path); 42 } 43 } 44 @Override 45 public void onScroll(AbsListView view, int firstVisibleItem, 46 int visibleItemCount, int totalItemCount) { 47 // TODO Auto-generated method stub 48 //如果已经划出去的列表项和正在显示的列表项==全部列表项,说明列表到达底部 49 isEnd = (firstVisibleItem+visibleItemCount)==totalItemCount; 50 } 51 }); 52 53 54 } 55 56 57 58 }
效果图: