RSS阅读器的Logo:
RSS阅读器是一种软件或是说一个程序,这种软件可以自由读取RSS和Atom两种规范格式的文档,且这种读取RSS和Atom文档的软件有多个版本,由不同的人或公司开发,有着不同的名字。如目前流行的有:RSSReader、Feeddemon、SharpReader等。这些软件能够实现大致相同的功能,其实质都是为了方便地读取RSS和Atom文档。Really Simple Syndication “聚合真的很简单”就是RSS的英文原意。把新闻标题、摘要(Feed)、内容按照用户的要求,“送”到用户的桌面就是RSS的目的。
注:下面给出的这个例子来自Google Android SDK开发,经过阅读,理解,并加上自己的和汇总写下这篇文章。
首先,给出实现本实例的截图,我用这个阅读器打开了我的博客。
1.
这是程序运行的主界面,实现这个界面的代码如下:
package irdc.ex08_13;
/* import相关class */
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class EX08_13 extends Activity
{
/* 变量声明 */
private Button mButton;
private EditText mEditText;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/* 初始化对象 */
mEditText=(EditText) findViewById(R.id.myEdit);
mButton=(Button) findViewById(R.id.myButton);
/* 设定Button的onClick事件 */
mButton.setOnClickListener(new Button.OnClickListener()
{
@Override
public void onClick(View v)
{
String path=mEditText.getText().toString();
if(path.equals(""))
{
showDialog("网址不可为空白!");
}
else
{
/* new一个Intent对象,并指定class */
Intent intent = new Intent();
intent.setClass(EX08_13.this,EX08_13_1.class);
/* new一个Bundle对象,并将要传递的数据传入 */
Bundle bundle = new Bundle();
bundle.putString("path",path);
/* 将Bundle对象assign给Intent */
intent.putExtras(bundle);
/* 调用Activity EX08_13_1 */
startActivityForResult(intent,0);
}
}
});
}
/* 重写 onActivityResult()*/
@Override
protected void onActivityResult(int requestCode,int resultCode,
Intent data)
{
switch (resultCode)
{
/*
* 当由主程序唤起的EX08_13_1发生运行错误时,会返回resultCode=99的信息,主程序
* 在接收到信息时,将以Dialog显示错误信息
*/
case 99:
/* 回传错误时以Dialog显示 */
Bundle bunde = data.getExtras();
String error = bunde.getString("error");
showDialog(error);
break;
default:
break;
}
}
/* 显示Dialog的method */
private void showDialog(String mess){
new AlertDialog.Builder(EX08_13.this).setTitle("Message")
.setMessage(mess)
.setNegativeButton("确定", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
}
})
.show();
}
}
说明:
* 这是一个ListActivity,主要用来显示订阅的RSS内容列表
* 当程序被主程序唤醒时,会先从Bundle对象中取得主程序传入的RSS网址,再调用自定义的getRss()方法
* 对RSS网址发出request,并解析由服务器返回的XML格式的文件。
* getRss()是自定义的方法,它除了会将RSS的request传送出去,在接收到服务器response时,会以
* SAXParser作为解析XML的主要工具,利用自定义的MyHandler类来取得XML内的相关信息。
* 调用getRss()时,会返回一个List
* 在取得List
* 程序中重写ListActivity的onListItemClick(),当ListView中的任一个item被单击时,onClick()会被触发,
* 此时会先取得单击的News对象,并将相关信息传入Bundle中,再将Bundle对象assign给Intent,并唤起EX08_13_2这个
* Activity。
* 当程序发生错误时,会返回resultCode=99的信息给上一个Activity
下面给出实现代码:
public class EX08_13_1 extends ListActivity
{
/* 变量声明 */
private TextView mText;
private String title="";
private List li=new ArrayList();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* 设定layout为newslist.xml */
setContentView(R.layout.newslist);
mText=(TextView) findViewById(R.id.myText);
/* 取得Intent中的Bundle对象 */
Intent intent=this.getIntent();
Bundle bunde = intent.getExtras();
/* 取得Bundle对象中的数据 */
String path = bunde.getString("path");
/* 调用getRss()取得解析后的List */
li=getRss(path);
mText.setText(title);
/* 设定自定义的MyAdapter */
setListAdapter(new MyAdapter(this,li));
}
/* 设定ListItem被按下时要做的动作 */
@Override
protected void onListItemClick(ListView l,View v,int position,
long id)
{
/* 取得News对象 */
News ns=(News)li.get(position);
/* new一个Intent对象,并指定class */
Intent intent = new Intent();
intent.setClass(EX08_13_1.this,EX08_13_2.class);
/* new一个Bundle对象,并将要传递的数据传入 */
Bundle bundle = new Bundle();
bundle.putString("title",ns.getTitle());
bundle.putString("desc",ns.getDesc());
bundle.putString("link",ns.getLink());
/* 将Bundle对象assign给Intent */
intent.putExtras(bundle);
/* 调用Activity EX08_13_2 */
startActivity(intent);
}
/* 剖析XML的method */
private List getRss(String path)
{
List data=new ArrayList();
URL url = null;
try
{
url = new URL(path);
/* 产生SAXParser对象 */
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
/* 产生XMLReader对象 */
XMLReader xr = sp.getXMLReader();
/* 设定自定义的MyHandler给XMLReader */
MyHandler myExampleHandler = new MyHandler();
xr.setContentHandler(myExampleHandler);
/* 解析XML */
xr.parse(new InputSource(url.openStream()));
/* 取得RSS标题与内容列表 */
data =myExampleHandler.getParsedData();
title=myExampleHandler.getRssTitle();
}
catch (Exception e)
{
/* 发生错误时回传result回上一个activity */
Intent intent=new Intent();
Bundle bundle = new Bundle();
bundle.putString("error",""+e);
intent.putExtras(bundle);
/* 错误的回传值设定为99 */
EX08_13_1.this.setResult(99, intent);
EX08_13_1.this.finish();
}
return data;
}
}
* 自定义的Handler对象,用来解析XML文件,并取得文件中的相关信息
* RSS返回的XML文件中,每一则新闻内容的起始为
*
*
*
*
* 新闻连接
*
*
*
*
* MyHandler在解析上述XML文件内容的流程如下:
* 1.运行startDocument(),生成一个List
* 2.当程序解析到Element的起始时,会运行startElement(),程序依据Element名称的不同,将其所对应的boolean
* 参数设置为true。
* 3.当程序解析到文件中的字符时(character),会运行characters()这个方法,将字符附加到(append)StringBuffer中
* 4.当程序解析到Element的结尾时会运行endElement(),程序依据Element名称的不同,将由StringBuffer转换成的字符串,
* 以setXXX()的方式把该属性写入News对象中,并把相对应的boolean变量设置为false。
实现代码如下:
public class MyHandler extends DefaultHandler
{
/* 变量声明 */
private boolean in_item = false;
//News对象的四个属性标记
private boolean in_title = false;
private boolean in_link = false;
private boolean in_desc = false;
private boolean in_date = false;
private boolean in_mainTitle = false;
private List li;
private News news;
private String title="";
private StringBuffer buf=new StringBuffer();
/* 将转换成List的XML数据回传 */
public List getParsedData()
{
return li;
}
/* 将解析出的RSS title回传 */
public String getRssTitle()
{
return title;
}
/* XML文件开始解析时调用此method */
@Override
public void startDocument() throws SAXException
{
li = new ArrayList();
}
/* XML文件结束解析时调用此method */
@Override
public void endDocument() throws SAXException
{
}
/* 解析到Element的开头时调用此method */
@Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException
{
if (localName.equals("item"))
{
this.in_item = true;
/* 解析到item的开头时new一个News对象 */
news=new News();
}
else if (localName.equals("title"))
{
if(this.in_item)
{
this.in_title = true;
}
else
{
this.in_mainTitle = true;
}
}
else if (localName.equals("link"))
{
if(this.in_item)
{
this.in_link = true;
}
}
else if (localName.equals("description"))
{
if(this.in_item)
{
this.in_desc = true;
}
}
else if (localName.equals("pubDate"))
{
if(this.in_item)
{
this.in_date = true;
}
}
}
/* 解析到Element的结尾时调用此method */
@Override
public void endElement(String namespaceURI, String localName,
String qName) throws SAXException
{
if (localName.equals("item"))
{
this.in_item = false;
/* 解析到item的结尾时将News对象写入List中 */
li.add(news);
}
else if (localName.equals("title"))
{
if(this.in_item)
{
/* 设定News对象的title */
news.setTitle(buf.toString().trim());
buf.setLength(0);
this.in_title = false;
}
else
{
/* 设定RSS的title */
title=buf.toString().trim();
buf.setLength(0);
this.in_mainTitle = false;
}
}
else if (localName.equals("link"))
{
if(this.in_item)
{
/* 设定News对象的link */
news.setLink(buf.toString().trim());
buf.setLength(0);
this.in_link = false;
}
}
else if (localName.equals("description"))
{
if(in_item)
{
/* 设定News对象的description */
news.setDesc(buf.toString().trim());
buf.setLength(0);
this.in_desc = false;
}
}
else if (localName.equals("pubDate"))
{
if(in_item)
{
/* 设定News对象的pubDate */
news.setDate(buf.toString().trim());
buf.setLength(0);
this.in_date = false;
}
}
}
/* 取得Element的开头结尾中间夹的字符串 */
@Override
public void characters(char ch[], int start, int length)
{
if(this.in_item||this.in_mainTitle)
{
/* 将char[]加入StringBuffer */
buf.append(ch,start,length);
}
}
}
* 这是一个JavaBean的类,用来存放每一篇新闻的详细信息。简单的说,每一个News对象就代表了一则新闻,News对象中的
*定义了的四个属性
*1.新闻的标题_title
*2.新闻的描述_desc
*3.网站的连接_link
*4.发布时间_date
public class News
{
/* News的四个变数 */
private String _title="";
private String _link="";
private String _desc="";
private String _date="";
public String getTitle()
{
return _title;
}
public String getLink()
{
return _link;
}
public String getDesc()
{
return _desc;
}
public String getDate()
{
return _date;
}
public void setTitle(String title)
{
_title=title;
}
public void setLink(String link)
{
_link=link;
}
public void setDesc(String desc)
{
_desc=desc;
}
public void setDate(String date)
{
_date=date;
}
}
package irdc.ex08_13;
/* import相关class */
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
/* 自定义的Adapter,继承android.widget.BaseAdapter */
public class MyAdapter extends BaseAdapter
{
/* 变量声明 */
private LayoutInflater mInflater;
private List items;
/* MyAdapter的建构子,传入两个参数 */
public MyAdapter(Context context,List it)
{
/* 参数初始化 */
mInflater = LayoutInflater.from(context);
items = it;
}
/* 因继承BaseAdapter,需重写以下method */
@Override
public int getCount()
{
return items.size();
}
@Override
public Object getItem(int position)
{
return items.get(position);
}
@Override
public long getItemId(int position)
{
return position;
}
@Override
public View getView(int position,View convertView,ViewGroup par)
{
ViewHolder holder;
if(convertView == null)
{
/* 使用自定义的news_row作为Layout */
convertView = mInflater.inflate(R.layout.news_row, null);
/* 初始化holder的text与icon */
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
News tmpN=(News)items.get(position);
holder.text.setText(tmpN.getTitle());
return convertView;
}
/* class ViewHolder */
private class ViewHolder
{
TextView text;
}
}
我们只需要点击其中的链接,就可以打开相应的网页文件,截图如下:
实现的代码如下:
注意,打开网页是调用系统自带的浏览器:
package irdc.ex08_13;
/* import相关class */
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.util.Linkify;
import android.widget.TextView;
public class EX08_13_2 extends Activity
{
/* 变量声明 */
private TextView mTitle;
private TextView mDesc;
private TextView mLink;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
/* 设定layout为newscontent.xml */
setContentView(R.layout.newscontent);
/* 初始化对象 */
mTitle=(TextView) findViewById(R.id.myTitle);
mDesc=(TextView) findViewById(R.id.myDesc);
mLink=(TextView) findViewById(R.id.myLink);
/* 取得Intent中的Bundle对象 */
Intent intent=this.getIntent();
Bundle bunde = intent.getExtras();
/* 取得Bundle对象中的数据 */
mTitle.setText(bunde.getString("title"));
mDesc.setText(bunde.getString("desc")+"....");
mLink.setText(bunde.getString("link"));
/* 设定mLink为网页连结 */
Linkify.addLinks(mLink,Linkify.WEB_URLS);
}
}