使用android解析技術解析網絡中的xml文件並以列表的形式顯示出來,實現效果如下:
首先在主要的xml中做好佈局,代碼如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/itemlist"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</RelativeLayout>
編寫實體類RssFeed.java,代碼如下:
package cn.bzu.saxparseraccess_listshow.entity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class RssFeed {
private String title;//標題
private String pubdate;//發佈日期
private int itemCount;//用於計算列表的數目
private List<RssItem> rssItems ;//用於描述列表 item
public RssFeed() {
//加入對象的創建
rssItems=new ArrayList<RssItem>();
}
//返回列表的長度 添加RssItem條目
public int addItem(RssItem item){
rssItems.add(item);
itemCount++;
return itemCount;
}
//根據下標獲取RssItem
public RssItem getItem(int location){
return rssItems.get(location);
}
//爲ListView 設置HashMap<String,Object>
public List<HashMap<String, Object>> getAllItemsForListView(){
List<HashMap<String,Object>> data=new ArrayList<HashMap<String,Object>>();
int size=rssItems.size();
for (int i = 0; i < size; i++) {
HashMap<String, Object> item=new HashMap<String, Object>();
item.put(RssItem.TITLE, rssItems.get(i).getTitle());
item.put(RssItem.PUBDATE, rssItems.get(i).getPubdate());
data.add(item);
}
return data;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getPubdate() {
return pubdate;
}
public void setPubdate(String pubdate) {
this.pubdate = pubdate;
}
public int getItemCount() {
return rssItems.size();
}
public List<RssItem> getRssItems() {
return rssItems;
}
}
編寫實體類RssItem.java,代碼如下:
package cn.bzu.saxparseraccess_listshow.entity;
public class RssItem {
public static final String TITLE="title";
public static final String PUBDATE="pubdate";
private String title;
private String description;
private String link;
private String category;
private String pubDate;
public RssItem() {
}
public String getTitle() {
if(title.length()>20){
return title.substring(0, 19)+"...";
}
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getPubdate() {
return pubDate;
}
public void setPubdate(String pubDate) {
this.pubDate = pubDate;
}
@Override
public String toString() {
return "RssItem [title=" + title + ", description=" + description
+ ", link=" + link + ", category=" + category + ", pubdate="
+ pubDate + "]";
}
}
編寫RssFeed_SAXParser.java,代碼如下:
package cn.bzu.saxparseraccess_listshow.saxparser;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.XMLReader;
import cn.bzu.saxparseraccess_listshow.entity.RssFeed;
import cn.bzu.saxparseraccess_listshow.service.RssHandler;
public class RssFeed_SAXParser {
public RssFeed getFeed(String urlStr) throws MalformedURLException, Exception, SAXException{//需要穿一個URL地址
URL url=new URL(urlStr);
System.out.println("RssFeed_SAXParser-->url:"+url);
SAXParserFactory parserFactory=SAXParserFactory.newInstance();//構建sax解析工廠
SAXParser saxParser=parserFactory.newSAXParser();//解析工廠生產解析器
XMLReader xmlReader=saxParser.getXMLReader();//通過saxParser構建xmlReader閱讀器
//構建自定義的xml解析器 作爲 xmlReader的處理器(代理)
RssHandler rssHandler=new RssHandler();
xmlReader.setContentHandler(rssHandler);
//使用url打開流,並將流作爲 xmlReader解析的輸入源並解析
InputSource is=new InputSource(url.openStream());
xmlReader.parse(is);
return rssHandler.getRssFeed();
}
}
在service層中編寫RssHandler.java,代碼如下:
package cn.bzu.saxparseraccess_listshow.service;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import android.util.Log;
import cn.bzu.saxparseraccess_listshow.entity.RssFeed;
import cn.bzu.saxparseraccess_listshow.entity.RssItem;
public class RssHandler extends DefaultHandler {
RssFeed rssFeed;// 用於保存解析過程中的channel
RssItem rssItem;// 用於保存解析過程中的item
String lastElementName = "";// 標記變量,用於標記在解析過程中我們關心的幾個標籤,若不是我們關心的標籤記做0
final int RSS_TITLE = 1;// 若是 title 標籤,記做1,注意有兩個title,但我們都保存在item的成員變量中
final int RSS_LINK = 2;// 若是 link 標籤,記做2
final int RSS_DESCRIPTION = 3;// 若是 description 標籤,記做3
final int RSS_CATEGORY = 4;// 若是category標籤,記做 4
final int RSS_PUBDATE = 5; // 若是pubdate標籤,記做
// 5,注意有兩個pubdate,但我們都保存在item的pubdate成員變量中
int currentstate = 0;
public RssHandler() {
}
// 下面通過重載 DefaultHandler 的 5 個方法來實現 sax 解析
// 1. 這個方法在解析xml文檔的一開始執行,一般我們需要在該方法中初始化解析過程中有可能用到的變量
@Override
public void startDocument() throws SAXException {
super.startDocument();
rssFeed = new RssFeed();
rssItem = new RssItem();
}
// 2. 當遇到文本結點時進行處理,空白符不用做處理,只需要對字符做處理
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
super.characters(ch, start, length);
// 獲取字符串
String text = new String(ch, start, length);
Log.i("i", "要獲取的內容:"+text);
// 判斷當前標誌位 與那一種標誌相同,然後做相應處理
switch (currentstate) {
case RSS_TITLE:
rssItem.setTitle(text);
currentstate = 0;// 設置完後,重置爲開始狀態
break;
case RSS_PUBDATE:
rssItem.setPubdate(text);
currentstate = 0;// 設置完後,重置爲開始狀態
break;
case RSS_CATEGORY:
rssItem.setCategory(text);
currentstate = 0;// 設置完後,重置爲開始狀態
break;
case RSS_LINK:
rssItem.setLink(text);
currentstate = 0;// 設置完後,重置爲開始狀態
break;
case RSS_DESCRIPTION:
rssItem.setDescription(text);
currentstate = 0;// 設置完後,重置爲開始狀態
break;
default:
break;
}
}
/**
* 3. 這個方法在解析標籤開始標記時執行,一般我們需要在該方法取得標籤屬性值,但由於我們的rss文檔
* 中並沒有任何我們關心的標籤屬性,因此我們主要在這裏進行的是設置標記變量currentstate, 以 標記我們處理到哪個標籤
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
// localName:不含命名空間前綴的標籤名(建議使用)
// qName:含有命名空間前綴的標籤名
// attributes:接收屬性值
if ("chanel".equals(localName)) {// 這個標籤內沒有我們關心的內容,所以不作處理,currentState=0
currentstate = 0;
return;
}
if ("item".equals(localName)) {
/*
* 若是item標籤,則重新構造一個RSSItem,從而把已有(已經解析過的)item數據扔掉, 當
* 然事先是已經保存到rssFeed的itemlist集合中
*/
rssItem = new RssItem();
return;
}
if ("title".equals(localName)) {
// 若是title標籤,置currentstate爲1,表明這是我們關心的數據,
// 這樣在characters 方法中會把元素內容保存到rssItem變量中
currentstate = RSS_TITLE;
return;
}
if ("description".equals(localName)) {
currentstate = RSS_DESCRIPTION;
return;
}
if ("link".equals(localName)) {
currentstate = RSS_LINK;
return;
}
if ("pubdate".equals(localName)) {
currentstate = RSS_PUBDATE;
return;
}
if ("category".equals(localName)) {
currentstate = RSS_CATEGORY;
return;
}
}
// 4. 結束元素節點
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);
// 如果解析一個item節點結束,就將rssItem添加到rssFeed中。
if ("item".equals(localName)) {
rssFeed.addItem(rssItem);
return;
}
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
// 這個方法在整個xml文檔解析結束時執行,一般需要在該方法中返回或保存整個文檔解析解析結果,
// 但由於我們已經在解析過程中把結果保持在rssFeed中,所以這裏什麼也不做
}
public RssFeed getRssFeed() {
return rssFeed;
}
}
在主要的Activity中編寫如下代碼:
package cn.bzu.saxparseraccess_listshow.activity;
import java.net.MalformedURLException;
import org.xml.sax.SAXException;
import cn.bzu.saxparseraccess_listshow.activity.R;
import cn.bzu.saxparseraccess_listshow.entity.RssFeed;
import cn.bzu.saxparseraccess_listshow.entity.RssItem;
import cn.bzu.saxparseraccess_listshow.saxparser.RssFeed_SAXParser;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleAdapter;
public class MainActivity extends Activity implements OnItemClickListener{
// 從網絡獲取RSS地址
public final String RSS_URL = "http://blog.sina.com.cn/rss/1267454277.xml";
public final String tag = "RSSReader";
private RssFeed feed = null;
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.activity_main);
try {// 調用getFeed方法,從服務器取得rss提要
feed = new RssFeed_SAXParser().getFeed(RSS_URL);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
showListView(); // 把rss內容綁定到ui界面進行顯示
}
private void showListView() {
ListView itemlist = (ListView) findViewById(R.id.itemlist);
if (feed == null) {
setTitle("訪問的RSS無效");
return;
}
SimpleAdapter adapter = new SimpleAdapter(this,
feed.getAllItemsForListView(),
android.R.layout.simple_list_item_2, new String[] {
RssItem.TITLE, RssItem.PUBDATE }, new int[] {
android.R.id.text1, android.R.id.text2 });
itemlist.setAdapter(adapter); // listview綁定適配器
itemlist.setOnItemClickListener(this); // 設置itemclick事件代理
itemlist.setSelection(0);
}
public void onItemClick(AdapterView parent, View v, int position, long id) // itemclick事件代理方法
{
Intent itemintent = new Intent(this, ActivityShowDescription.class);// 構建一個“意圖”,用於指向activity
// :detail
Bundle b = new Bundle(); // 構建buddle,並將要傳遞參數都放入buddle
b.putString("title", feed.getItem(position).getTitle());
b.putString("description", feed.getItem(position).getDescription());
b.putString("link", feed.getItem(position).getLink());
b.putString("pubdate", feed.getItem(position).getPubdate());
itemintent.putExtra("android.intent.extra.rssItem", b); // 用android.intent.extra.INTENT的名字來傳遞參數
startActivityForResult(itemintent, 0);
}
}
添加activity_activity_show_description.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" >
<TextView
android:id="@+id/content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:autoLink="all"
android:text="" />
<Button
android:id="@+id/back"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="返回" />
</LinearLayout>
添加新的Activity(ActivityShowDescription),代碼如下:
package cn.bzu.saxparseraccess_listshow.activity;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.support.v4.app.NavUtils;
public class ActivityShowDescription extends Activity {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.activity_activity_show_description);
String content = null;
Intent startingIntent = getIntent();
if (startingIntent != null) {
Bundle bundle = startingIntent
.getBundleExtra("android.intent.extra.rssItem");
if (bundle == null) {
content = "不好意思程序出錯啦";
} else {
content = bundle.getString("title") + "\n\n"
+ bundle.getString("pubdate") + "\n\n"
+ bundle.getString("description").replace('\n', ' ')
+ "\n\n詳細信息請訪問以下網址:\n" + bundle.getString("link");
}
} else {
content = "不好意思程序出錯啦";
}
TextView textView = (TextView) findViewById(R.id.content);
textView.setText(content);
Button backbutton = (Button) findViewById(R.id.back);
backbutton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
finish();
}
});
}
}