RSS实例

57、RSS实例

SAX解析XML基本知识:

http://leequer.iteye.com/blog/653148


RSS也叫聚合RSS是在线共享内容的一种简易方式 ,RSS其实就是通过解析XML文件,把有效信息显示给用户的一种服务。

总体设计:

1、通过数据库存储RSS站点

2、默认提供一些站点,用户可以自己添加站点

3、在管理模式下可以编辑或删除站点(目前只完成删除)

首先定义布局:

1、入口程序继承ListActivity,这样可以不需要在onCreate方法中设置setContentView()。

2、在onListItemClick()中添加点击ListView时的事件:启动另一个ActivityShowRSSItems用来显示对用的RSS条目。

3、在ShowRSSItems中用ListView来进行显示,点击每个条目之后进入另一个ActivityShowDescription,用WebView来显示内容,并放置一个返回按钮。

4、数据库的初始化在SSData extends SQLiteOpenHelper中的onCreate完成,即建立表和初始化数据。注意,程序在打包发布的时候,数据库里的内容是会被清除的,如果在MainActivity中进行数据的初始化,那么在调试程序的时候当数据库中已经有数据时必须将这些代码注释掉。但一旦打包发布后,数据库里的内容就消失了,所以在RSSData中进行。

5、在管理模式中,ListView每一个项的右边都有一个删除的图标,用户点击这个图标可以进行删除操作,这个图标其实是一个设置了背景属性为一张png图标的Button。这里参考了网上的布局方法,自定义了Adapter,它继承了BaseAdapter,主要是重写一个叫getView()的方法:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.list_item_model, null);
holder.img = (ImageView) convertView.findViewById(R.id.img);
holder.title = (TextView) convertView.findViewById(R.id.title);
holder.link = (TextView) convertView.findViewById(R.id.link);
holder.moreBtn = (Button) convertView
.findViewById(R.id.list_but);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.title.setText((String) URL_List.get(position)
.get(RSS_T_L[0]));
holder.link
.setText((String) URL_List.get(position).get(RSS_T_L[1]));
String rid = URL_List.get(position).get(RSSID).toString();
holder.moreBtn.setContentDescription(rid + "/"
+ (String) URL_List.get(position).get(RSS_T_L[0]));
holder.moreBtn.setBackgroundResource(R.drawable.del3);
holder.moreBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Button current = (Button) v;
String desc = current.getContentDescription().toString();
String desc_arr[] = desc.split("/");
showInfo(desc_arr[0], desc_arr[1]);
}
});
return convertView;
}


6上面用到了布局文件list_item_model.xml,而不是用系统的布局,至于如何让ListView的每一行显示两小行数据(一个标题一个链接),则需要灵活设置布局文件以及字体的大小:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView android:id="@+id/img" 
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" 
  android:layout_margin="5px"/>
  
<LinearLayout
android:orientation="vertical" 
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22dip"
/>
<TextView
android:id="@+id/link"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="13dip"
/>
</LinearLayout>
<RelativeLayout
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
>
<Button android:id="@+id/list_but"
  android:layout_width="24px"
  android:layout_height="24px"
  android:focusable="false"
  android:layout_gravity="center|right"
  android:layout_alignParentRight="true"
  />
</RelativeLayout>
</LinearLayout>


7、如何知道每个按钮是跟ListView中的每一项对应起来的呢,这里用到了按钮的setContentDescription(String desc)方法,在初始化每一个按钮的时候变给它设置了setContentDescription,传入每一URL_List的ID以及title,可以用‘/’隔开,取数据的时候再根据‘/’来进行分割,如:

holder.moreBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Button current = (Button) v;
String desc = current.getContentDescription().toString();
String desc_arr[] = desc.split("/");
showInfo(desc_arr[0], desc_arr[1]);
}
});


8、添加站点

添加站点的布局倒花费了不少时间,主要是对布局的不熟悉,总结一下心得:

1、让TextView的文字居中显示:

可以在该TextView外面再加多一层RelativeLayout,然后让TextView的属性如下所示:

    <TextView
        android:layout_width="wrap_content"
     	android:layout_height="wrap_content"
     	android:text="@string/add_rss"
     	android:textStyle="bold"
     	android:textSize="22dip"
     	android:layout_centerInParent="true"
 android:layout_margin="30dip"/>


主要是

android:layout_width="wrap_content" 和

android:layout_centerInParent="true"

2、TableLayout中 android:stretchColumns="0,1"是然TableRow中的第一列跟第二列自动适应并填满。

   <TableLayout
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:stretchColumns="0,1"
      android:layout_margin="15dip"
      >  
<TableRow>
   	<Button
   	 android:id="@+id/but_add"
   	 android:text="@string/but_add"/>
   	<Button
   	 android:id="@+id/but_cancle"
   	 android:text="@string/but_cancle" />
</TableRow>
  </TableLayout>


9、还有一点很重要的就是ListView对数据的刷新:

不要在onCreate中进行刷新操作,因为onCreate只是在第一个建立该Actiivity时才运行一次的。那么可以在onResume和onPause()中进行刷新操作:

@Override
protected void onResume() {
URL_List = new ArrayList<Map<String, Object>>();
SQLiteDatabase sdb = rd.getReadableDatabase();
URL_List = showRSSList(sdb);
// showRSSList(sdb);
// adapter.notifyDataSetChanged();
// itemlist.setAdapter(adapter);
MyAdapter adapter = new MyAdapter(this);
setListAdapter(adapter);
super.onResume();
}
@Override
protected void onPause() {
/*
 * 网上说下面这种方法可以奏效,不过试了没用,可能用法有些不正确,故采用了重新调用
 * showRSSList(),不过要让适配器的第二个参数(即这里的URL_List)清空,否则新内容 会追加到ListView后面
 */
// adapter.notifyDataSetChanged();
// itemlist.setAdapter(adapter);
URL_List = new ArrayList<Map<String, Object>>();
SQLiteDatabase sdb = rd.getReadableDatabase();
URL_List = showRSSList(sdb);
// showRSSList(sdb);
MyAdapter adapter = new MyAdapter(this);
setListAdapter(adapter);
super.onPause();
}


10、程序的菜单设计在res/menu中进行设计比较简单:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/add_item"
  android:title="@string/add_rss"
  android:icon="@drawable/add"/>
  
<item android:id="@+id/manager"
  android:title="@string/manager"
  android:icon="@drawable/manage"/>
<item android:id="@+id/flush"
  android:title="@string/flush"
  android:icon="@drawable/flush"/>	 
   
<item android:id="@+id/about"
  android:title="@string/about"
  android:icon="@drawable/about"/>
</menu>


下面是对应的相应事件:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// return super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case R.id.add_item:
this.startActivity(new Intent(this, RSSAddItem.class));
return true;
case R.id.manager:
// holder.moreBtn.setBackgroundResource(R.drawable.del3);
Intent manager = new Intent(this, ManagerModel.class);
this.startActivity(manager);
// b.putParcelableArrayList("URL_List", URL_List);
break;
case R.id.about:
new AlertDialog.Builder(this).setTitle("关于 MyRSS").setMessage(
"MyRSS为您提供了新闻阅读功能,默认提供了人民网九大新闻频道,"
+ "让您轻松掌握具有权威性、及时性、多样性的新闻资讯!您也可以随时增加或删除RSS站点!/n"
+ "版本:1.1/n作者:天蓝/nQQ:349903386/n有任何疑问请联系我!")
.setPositiveButton("确定",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
}
}).show();
break;
case R.id.flush:
this.onResume();
break;
}
return false;
}


11、最后是程序的核心咯,也就是如何用SAX来解析XML文件,这里分四步走:

1、建立一个类似JavaBean的类(RSSItem.java),用于描述一个XML文件中的标签,如:

public static final String TITLE = "title";

public static final String PUBDATE = "pubdate";

private String title = null;

private String description = null;

private String link = null;

private String category = null;

private String pubdate = null;

然后给出这些字段的getset方法。

2、建立一个与XML文件对应的类(RSSView.java):

public class RSSView {
private String title = null;
private String pubdate = null;
private int itemcount = 0;
private List<RSSItem> itemlist;
public RSSView() {
itemlist = new Vector(0);
}
public int addItem(RSSItem item) {
itemlist.add(item);
itemcount++;
return itemcount;
}
public RSSItem getItem(int location) {
return itemlist.get(location);
}
public List getAllItems() {
return itemlist;
}
public List getAllItemForListView() {
List<Map<String, Object>> data = new ArrayList<Map<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 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;
}
}


3、第三步是最重要的一步,即定义一个Handler,继承DefaultHandler:

public class RSSHandler extends DefaultHandler {
RSSView _RSSView;
RSSItem _RSSItem;
String lastElementName = "";
final int RSS_TITLE = 1;
final int RSS_LINK = 2;
final int RSS_DESCRIPTION = 3;
final int RSS_CATEGORY = 4;
final int RSS_PUBDATE = 5;
int currentstate = 0;
public RSSHandler() {
}
public RSSView getRSSListView() {
return _RSSView;
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
String theString = new String(ch, start, length);
switch (currentstate) {
case RSS_TITLE:
_RSSItem.setTitle(theString);
currentstate = 0;
break;
case RSS_LINK:
_RSSItem.setLink(theString);
currentstate = 0;
break;
case RSS_DESCRIPTION:
_RSSItem.setDescription(theString);
currentstate = 0;
break;
case RSS_CATEGORY:
_RSSItem.setCategory(theString);
currentstate = 0;
break;
case RSS_PUBDATE:
_RSSItem.setPubdate(theString);
currentstate = 0;
break;
default:
return;
}
// super.characters(ch, start, length);
}
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
// super.endDocument();
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (localName.equals("item")) {
_RSSView.addItem(_RSSItem);
return;
}
// super.endElement(uri, localName, qName);
}
@Override
public void startDocument() throws SAXException {
_RSSView = new RSSView();
_RSSItem = new RSSItem();
// super.startDocument();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
if (localName.equals("item")) {
_RSSItem = new RSSItem();
return;
}
if (localName.equals("channel")) {
currentstate = 0;
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;
// super.startElement(uri, localName, qName, attributes);
}
}
4、在ShowRSSItems.java中用SAX API来操作:
public class ShowRSSItems extends Activity implements OnItemClickListener {
private RSSView rssview = null;
String RSS_TITLE = "";
String RSS_URL = "";
String RID = "";
TextView tv;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.show_rss_item);
tv = (TextView) this.findViewById(R.id.rsstextview_);
// 根据选择的站点加载数据
// RSS_URL = this.getIntent().getExtras().getString("A_RSS_INFO");
Bundle bundle = this.getIntent().getBundleExtra("A_RSS_INFO");
if (bundle != null) {
RSS_TITLE = bundle.getString(RSSMainActivity.RSS_T_L[0]);
RSS_URL = bundle.getString(RSSMainActivity.RSS_T_L[1]);
RID = bundle.getString(RSSID);
// this.setTitle(RSS_TITLE + "(ID:" + RID + ")");
this.setTitle(RSS_TITLE);
} else {
tv.setText("不好意思,程序出错啦!");
return;
}
rssview = getRssView(RSS_URL);
showListView();
}
private RSSView getRssView(String urlString) {
try {
URL url = new URL(urlString);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
RSSHandler rssHandler = new RSSHandler();
xmlreader.setContentHandler(rssHandler);
InputSource inputsource = new InputSource(url.openStream());
xmlreader.parse(inputsource);
return rssHandler.getRSSListView();
} catch (Exception ee) {
tv.setText(RSS_URL + "/n" + ee.toString());
return null;
}
}
private void showListView() {
ListView itemlist = (ListView) findViewById(R.id.rssItemView);
if (rssview == null) {
setTitle("访问RSS无效!");
return;
}
SimpleAdapter adapter = new SimpleAdapter(this, rssview
.getAllItemForListView(), 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);
itemlist.setOnItemClickListener(this);
itemlist.setSelection(0);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Intent itemintent = new Intent(this, ShowDescription.class);
Bundle b = new Bundle();
b.putString("title", rssview.getItem(position).getTitle());
b.putString("description", rssview.getItem(position).getDescription());
b.putString("pubdate", rssview.getItem(position).getPubdate());
b.putString("link", rssview.getItem(position).getLink());
itemintent.putExtra("Android.intent.extra.RSSItem", b);
this.startActivityForResult(itemintent, 0);
}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值