RSS阅读器的实现

紧接上一篇文章的内容,实现了RSS阅读器就可以直接阅读网上的xml内容了。

首先,根据xml设计布局文件:

main_activity:

<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>


show_activity:

<?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>


第二,完成实体类,用以直接操作实现:

RSSFeed类:

public class RSSFeed {
	private String title;//标题
	private String pubdate;//发布日期
	private int itemcount;//用于计算列表的数目
	private List<RSSItem> itemlist;//用于描述列表

	public RSSFeed() {
		//加入对象的创建
		itemlist = new ArrayList<RSSItem>();
	}

	public int addItem(RSSItem item) {
		itemlist.add(item);
		itemcount++;
		return itemcount;
	}
	//根据下标获取RssItem
	public RSSItem getItem(int location) {
		return itemlist.get(location);
	}
	//为ListView 设置HashMap<String,Object>
	public List<HashMap<String, Object>> getAllItemsForListView() {
		List<HashMap<String, Object>> data = new ArrayList<HashMap<String, Object>>();
		int size = itemlist.size();
		for (int i = 0; i < size; i++) {
			HashMap<String, Object> item = new HashMap<String, Object>();
			item.put(RSSItem.TITLE, itemlist.get(i).getTitle());
			item.put(RSSItem.PUBDATE, itemlist.get(i).getPubdate());
			data.add(item);
		}
		return data;
	}

	public int getItemCount() {
		return itemlist.size();
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public void setPubDate(String pubdate) {
		this.pubdate = pubdate;
	}

	public String getTitle() {
		return title;
	}

	public String getPubDate() {
		return pubdate;
	}
	public List<RSSItem> getRssItems() {
		return itemlist;
	}

}


RSSItem类:

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 + "]";
		
	}

}

 

第三,实体解析类:

 

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.getFeed();
	}
}

 

实现ContentHandler(RssHandler类):

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文档的一开始执行,一般我们需要在该方法中初始化解析过程中有可能用到的变量
	public void startDocument() throws SAXException {
		super.startDocument();
		RSSFeed = new RSSFeed();
		RSSItem = new RSSItem();
	}
	// 2. 当遇到文本结点时进行处理,空白符不用做处理,只需要对字符做处理
	@Override
	public void characters(char[] ch, int start, int length) {
		String theString = new String(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_LINK:
			RSSItem.setLink(text);
			currentstate = 0;// 设置完后,重置为开始状态
			break;
		case RSS_DESCRIPTION:
			RSSItem.setDescription(text);
			currentstate = 0;// 设置完后,重置为开始状态
			break;
		case RSS_CATEGORY:
			RSSItem.setCategory(text);
			currentstate = 0;// 设置完后,重置为开始状态
			break;
		case RSS_PUBDATE:
			RSSItem.setPubdate(text);
			currentstate = 0;// 设置完后,重置为开始状态
			break;
		default:
			return;
		}
	}
	/**
	 * 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 (localName.equals("channel")) {
			currentstate = 0;
			return;
		}
		if (localName.equals("item")) {
			RSSItem = new RSSItem();
			return;
		}
		if (localName.equals("title")) {
			currentstate = RSS_TITLE;
			return;
		}
		if (localName.equals("description")) {
			currentstate = RSS_DESCRIPTION;
			return;
		}
		if (localName.equals("link")) {
			currentstate = RSS_LINK;
			return;
		}
		if (localName.equals("category")) {
			currentstate = RSS_CATEGORY;
			return;
		}
		if (localName.equals("pubdate")) {
			currentstate = RSS_PUBDATE;
			return;
		}
		currentstate = 0;
	}

	// 4. 结束元素节点
	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		// 如果解析一个item节点结束,就将RSSItem添加到RSSFeed中
		if (localName.equals("item")) {
			RSSFeed.addItem(RSSItem);
			return;
		}
	}

	
	@Override
	public void endDocument() throws SAXException {
		super.endDocument();

		// 这个方法在整个xml文档解析结束时执行,一般需要在该方法中返回或保存整个文档解析解析结果,

		// 但由于我们已经在解析过程中把结果保持在rssFeed中,所以这里什么也不做

	}
	public RSSFeed getRssFeed() {
		return RSSFeed;
	}
	
}

 

第四,Activity实现:

ActivityMain:

public class ActivityMain extends Activity implements OnItemClickListener {
	public final String RSS_URL = "http://blog.sina.com.cn/rss/1267454277.xml";
	public final String tag = "RSSReader";
	private RSSFeed feed = null;

	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		setContentView(R.layout.activity_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

		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);
	}

}

ActivityShowDescription:

public class ActivityShowDescription extends Activity {

	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		setContentView(R.layout.show_activity);
		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();
			}
		});
	}

}


最后,运行前还要在AndroidManifest.xml中加入许可才能完成解析网上的xml文件:

 

<uses-permission android:name="android.permission.INTERNET" />



由于时间紧,具体的解析、结果、错误分析,请继续关注,以后会更新添加。

 注意,如下两图中的Extra命名必须一致:

《1,ActivityMain中》

《2,showDescription中》

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值