前言:

在开发的过程中,有时候我们需要从网络解析一些数据,比如最近的一些新闻,我们需要把这些数据用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中

先建一个房屋实体类




Android recylerview 列数不定 安卓多列listview_java

Android recylerview 列数不定 安卓多列listview_移动开发_02

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 }


Home.class


2、工具类(http获取数据,json数据解析)




Android recylerview 列数不定 安卓多列listview_java

Android recylerview 列数不定 安卓多列listview_移动开发_02

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 }


HttpUtil.class



Android recylerview 列数不定 安卓多列listview_java

Android recylerview 列数不定 安卓多列listview_移动开发_02

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 }


JsonString.class解析JSON数据


3、ListView的自定义适配器类




Android recylerview 列数不定 安卓多列listview_java

Android recylerview 列数不定 安卓多列listview_移动开发_02

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 }


MyAdapter.class


4、异步任务获得数据




Android recylerview 列数不定 安卓多列listview_java

Android recylerview 列数不定 安卓多列listview_移动开发_02

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 }


AsyncTaskHome.class


5、主Activity




Android recylerview 列数不定 安卓多列listview_java

Android recylerview 列数不定 安卓多列listview_移动开发_02

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 }


MainActivity.class


 

效果图:

 

Android recylerview 列数不定 安卓多列listview_json_13