从网络读取数据并动态的显示在ListView中
这里面有几个关键点:
从网络读取数据
SAX解析xml
异步填充ListView
先看下截图:
非常简单的界面哈
为了方便,我再自己的服务器上,放了一个xml文件,其内容主要是:
<?xml version="1.0"?>
<products>
<product>
<price>100</price>
<name>android dev</name>
<image src="image/android1.png"/>
</product>
<product>
<price>100</price>
<name>androiddev2</name>
<image src="image/android1.png"/>
</product>
<!-- 接着重复下去.... -->
</products>
该程序,首先用一个AsyncTask新启一个线程,来下载和解析xml;和主线程通过Handler对象来通讯。
下载XML文件
通过HTTPGet来下载xml。这时apache提供的包,需要首先包含如下包:
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
代码如下:(使用Get方法)
protected String doInBackground(String... params) {
HttpGet httpRequest = new HttpGet(params[0]); //从url 创建一个HttpGet对象
HttpClient httpclient = new DefaultHttpClient();
//mShowHtml.setText("");
try {
HttpResponse httpResponse = httpclient.execute(httpRequest);
if(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){//获取http的返回值代码
HttpEntity entitiy = httpResponse.getEntity();
InputStream in = entitiy.getContent();//获得内容
//解析xml,下面详述
InputSource source = new InputSource(in);
SAXParserFactory sax = SAXParserFactory.newInstance();
XMLReader xmlReader = sax.newSAXParser().getXMLReader();
xmlReader.setContentHandler(new ProductHandler());
xmlReader.parse(source);
}
else {
//return "请求失败!";
//mShowHtml.setText("请求失败");
//Message mymsg = mMainHandler.obtainMessage();
//mymsg.obj = "请求失败";
//mMainHandler.sendMessage(mymsg);
}
}catch(IOException e){
e.printStackTrace();
}catch(SAXException e) {
e.printStackTrace();
}catch(ParserConfigurationException e) {
e.printStackTrace();
}
return null;
}
解析XML
使用SAX的解析方法,先包含必须得包
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
解析的代码,正如上面所示:
//InputSource是解析源,可以通过一个InputStream创建
urce source = new InputSource(in);
SAXParserFactory sax = SAXParserFactory.newInstance();
der xmlReader = sax.newSAXParser().getXMLReader();
xmlReader.setContentHandler(new ProductHandler());//ProductHandler是解析的句柄
der.parse(source);
SAX主要使用ContentHandler接口来传递解析好得数据,不过,更经常使用的是DefaultHandler
class ProductHandler extends DefaultHandler { //从DefaultHandler继承即可
private ProductInfo curProduct;
private String content;
//解析到一个标签时调用
public void startElement(String uri, String localName, String name, org.xml.sax.Attributes attributes) throws SAXException {
if(localName.equals("product")) {//遇到product标签,进行解析
curProduct = new ProductInfo();
}
else if(localName.equals("image")) {
//set name
curProduct.image = attributes.getValue("src");//提取image src属性
}
super.startElement(uri, localName, name, attributes);
}
public void endElement(String uri, String localName, String name) throws SAXException{
if(localName.equals("product")) {//当解析到一个标签结束时,发送一个消息,把Product类作为参数传递
//send event
//get main handler
Message msg = mMainHandler.obtainMessage();
msg.obj = curProduct;
mMainHandler.sendMessage(msg);
//Log.i("Product:", curProduct.toString());
}
else if(localName.equals("name")) {
//set name
curProduct.name = content;//保存名字
}
else if(localName.equals("price")) {
curProduct.price = Float.parseFloat(content);<span style="background-color: rgb(255, 255, 255); ">//保存价格</span>
}
super.endElement(uri, localName, name);
}
//这里获取具体的内容,是标签下保存的文本
public void characters (char[] ch, int start, int length) throws SAXException
{
content = new String(ch, start, length);
//Log.i("Parser:" ,content);
super.characters(ch, start, length);
}
}
ProductInfo类的定义非常简单
class ProductInfo {
public String name;
public float price;
public String image;
public String toString() {
return "\nName:" + name +"\nPrice :" + price + "\nImage:" + image;
}
}
在AsyncTask中执行以上代码
public class GetHttpTask extends AsyncTask<String, Integer, String> {
public GetHttpTask() {
}
protected void onPreExecute() { //在进入线程之前执行。该函数在调用者线程内执行
}
protected String doInBackground(String... params) {//线程的执行主体
HttpGet httpRequest = new HttpGet(params[0]);
.................. //主要执行下载和解析的嗲吗
return null;
}
protected void onPostExecute(String result) {//完成后调用
}
}
在主线程中,调用GetHttpTask的execute方法就可以执行
btn.setOnClickListener(new View.OnClickListener() {//在onCreate函数中调用
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
httpGet();
}
});
httpGet方法:
void httpGet() {
GetHttpTask task = new GetHttpTask();
task.execute("http://192.168.1.111:8080/nfcdemo/products.xml");
}
异步传递消息
上面的例子中,在endElement函数中,发送了消息,下面是接收消息
在主Activity中,声明了一个Handler mHandler对象,并在onCreate时,这样做
mMainHandler = new Handler() {
public void handleMessage(Message msg) {
//mShowHtml.append((String)msg.obj);
if(msg.obj != null) {
ProductInfo prod = (ProductInfo)msg.obj;
Log.i("Prodcut:", prod.toString());
//mShowHtml.append(prod.toString());
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("name", prod.name);
map.put("price", "RMB" + prod.price);
mlist.add(map); //mlist保存了列表的具体数据
mProdList.notifyDataSetChanged();//mProdList是一个ListView对象,该函数引起ListView重读数据
}
}
};
这个过程的要点基本如上,贴上所有代码吧!关于ListView的用法,可以参考http://blog.csdn.net/hellogv/article/details/4542668
主代码:
package com.test.http;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
public class HtmltestActivity extends Activity {
EditText mUrlText;
//EditText mShowHtml;
ListView mProducts;
Handler mMainHandler;
SimpleAdapter mProdList;
ArrayList<HashMap<String,Object>> mlist;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mUrlText = (EditText)findViewById(R.id.eturl);
//mShowHtml = (EditText)findViewById(R.id.etshowhtml);
mProducts = (ListView)findViewById(R.id.productList);
Button btn = (Button)findViewById(R.id.btngo);
mlist = new ArrayList<HashMap<String, Object>>();
mProdList = new SimpleAdapter(this,
mlist,
R.layout.listitem,
new String[]{"name", "price"},
new int[]{R.id.prd_title, R.id.prd_price}
);
mProducts.setAdapter(mProdList);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
httpGet();
}
});
mMainHandler = new Handler() {
public void handleMessage(Message msg) {
//mShowHtml.append((String)msg.obj);
if(msg.obj != null) {
ProductInfo prod = (ProductInfo)msg.obj;
Log.i("Prodcut:", prod.toString());
//mShowHtml.append(prod.toString());
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("name", prod.name);
map.put("price", "RMB" + prod.price);
mlist.add(map);
mProdList.notifyDataSetChanged();
}
}
};
}
void httpGet() {
GetHttpTask task = new GetHttpTask();
task.execute("http://192.168.1.111:8080/nfcdemo/products.xml");
}
public class GetHttpTask extends AsyncTask<String, Integer, String> {
public GetHttpTask() {
}
protected void onPreExecute() {
}
protected String doInBackground(String... params) {
HttpGet httpRequest = new HttpGet(params[0]);
HttpClient httpclient = new DefaultHttpClient();
//mShowHtml.setText("");
try {
HttpResponse httpResponse = httpclient.execute(httpRequest);
if(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
HttpEntity entitiy = httpResponse.getEntity();
InputStream in = entitiy.getContent();
InputSource source = new InputSource(in);
SAXParserFactory sax = SAXParserFactory.newInstance();
XMLReader xmlReader = sax.newSAXParser().getXMLReader();
xmlReader.setContentHandler(new ProductHandler());
xmlReader.parse(source);
}
else {
//return "请求失败!";
//mShowHtml.setText("请求失败");
//Message mymsg = mMainHandler.obtainMessage();
//mymsg.obj = "请求失败";
//mMainHandler.sendMessage(mymsg);
}
}catch(IOException e){
e.printStackTrace();
}catch(SAXException e) {
e.printStackTrace();
}catch(ParserConfigurationException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String result) {
//mShowHtml.setText(result);
}
}
class ProductInfo {
public String name;
public float price;
public String image;
public String toString() {
return "\nName:" + name +"\nPrice :" + price + "\nImage:" + image;
}
}
class ProductHandler extends DefaultHandler {
private ProductInfo curProduct;
private String content;
public void startElement(String uri, String localName, String name, org.xml.sax.Attributes attributes) throws SAXException {
if(localName.equals("product")) {
curProduct = new ProductInfo();
}
else if(localName.equals("image")) {
//set name
curProduct.image = attributes.getValue("src");
}
super.startElement(uri, localName, name, attributes);
}
public void endElement(String uri, String localName, String name) throws SAXException{
if(localName.equals("product")) {
//send event
//get main handler
Message msg = mMainHandler.obtainMessage();
msg.obj = curProduct;
mMainHandler.sendMessage(msg);
//Log.i("Product:", curProduct.toString());
}
else if(localName.equals("name")) {
//set name
curProduct.name = content;
}
else if(localName.equals("price")) {
curProduct.price = Float.parseFloat(content);
}
super.endElement(uri, localName, name);
}
public void characters (char[] ch, int start, int length) throws SAXException
{
content = new String(ch, start, length);
//Log.i("Parser:" ,content);
super.characters(ch, start, length);
}
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<EditText
android:id="@+id/eturl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" >
<requestFocus />
</EditText>
<Button
android:id="@+id/btngo"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Go!" />
</LinearLayout>
<ListView
android:id="@+id/productList"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>
listitem.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/product_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/prd_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/product_icon"
android:text="TextView" />
<TextView
android:id="@+id/prd_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="TextView" />
</RelativeLayout>
doon的专栏