flyone

从现在到未来...
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Android项目之 RSS阅读器(1)

Posted on 2011-07-23 21:13  flyone  阅读(2535)  评论(1编辑  收藏  举报

   我的淘宝店铺,http://shop61982302.taobao.com/,欢迎大家光临!你懂的,呵呵!

    在这个项目系列中,我将详细说明每个项目的开发过程,以及项目涉及到的很多基础知识。这些项目都是网上或者书本上的,由于这些项目开发过程讲的不是很详细,涉及到基层知识又特别多,自己阅读起来比较费劲。我将自己读懂的地方详细注释出来,希望大家可以快速读懂,快速应用到实际项目中,阅读时能起到事半功倍,举一反三效果!他山之石可以攻玉,呵呵!

   第一个项目是RSS阅读器。运行效果如下图,显示的是我的博客的内容:

我的博客rss地址:http://www.cnblogs.com/flyone/rss,可以用google reader订阅

点击左边每一个条目都可以查看详细的内容,也就是跳转到第二个Activity,如下图

下面详细介绍开发过程,大家可以一步一步跟着我的截图来做:

1 新建一个工程:

2 在配置文件AndroidManifest.xml中,添加访问网络的权限,以及第二个activity信息,如下:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="com.fly.rss"

      android:versionCode="1"

      android:versionName="1.0">

    <uses-sdk android:minSdkVersion="8" />

    //下面是访问网络的权限

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

    <application android:icon="@drawable/icon" android:label="@string/app_name">

        <activity android:name=".act_RssDemo"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

      //第二个activity,显示博客详细内容

        <activity android:name=".ActivityShowDescription"></activity>

    </application>

</manifest>

3 设置主界面的布局文件Main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<!-- <TextView  

    android:layout_width="fill_parent" 

    android:layout_height="wrap_content" 

    android:text="@string/hello"

    /> -->

<!-- ListView 以列表的形式展示具体内容,并且能够根据数据的长度自适应显示

在这篇文章的后面会详细附上ListView的用法 -->

   <ListView

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:id="@+id/itemlist"

/> 

</LinearLayout>

4 设置第二个界面的布局文件showdescription.xml,利用向导创建即可:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<TextView  

    android:layout_width="fill_parent" 

    android:layout_height="wrap_content" 

    android:autoLink="all"

    android:text=""

    android:id="@+id/content"

    android:layout_weight="1.0"

    />

<Button

    android:layout_width="fill_parent" 

    android:layout_height="wrap_content" 

    android:text="返回"

android:id="@+id/back"

/>    

</LinearLayout>

5 新建一个类保存xml文件中标签内容,也就是博客中的rss内容,即是一个Java bean

package com.fly.rss.data;

public class RSSItem 

{

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

public RSSItem()

{

}

public void setTitle(String title)

{

this.title = title;

}

public void setDescription(String description)

{

this.description = description;

}

public void setLink(String link)

{

this.link = link;

}

public void setCategory(String category)

{

this.category = category;

}

public void setPubDate(String pubdate)

{

this.pubdate = pubdate;

}

public String getTitle()

{

return title;

}

public String getDescription()

{

return description;

}

public String getLink()

{

return link;

}

public String getCategory()

{

return category;

}

public String getPubDate()

{

return pubdate;

}

public String toString()

{

if (title.length() > 20)

{

return title.substring(0, 42) + "...";

}

return title;

}

}

6 新建类将item内容插入到list中

package com.fly.rss.data;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.Vector;

public class RSSFeed 

{

private String title = null;

private String pubdate = null;

private int itemcount = 0;

private List<RSSItem> itemlist;

public RSSFeed()

{

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;

}

      //将数据添加到list中以便于android控件listview建立关联

public List getAllItemsForListView(){

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;

}

int getItemCount()

{

return itemcount;

}

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;

}

}

7 新建一个解析xml文件的类,注意这个是关键:
package com.fly.rss.data.sax;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import android.util.Log;
import com.fly.rss.data.*;
//
public class RSSHandler extends DefaultHandler 
{
RSSFeed rssFeed;
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 RSSFeed getFeed()
{
return rssFeed;
}
        //开始文档时调用
public void startDocument() throws SAXException
{
               //实例化两个对象
rssFeed = new RSSFeed();
rssItem = new RSSItem();
}
public void endDocument() throws SAXException
{
}
public void startElement(String namespaceURI, String localName,String qName, Attributes atts) throws SAXException
{
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;
}
public void endElement(String namespaceURI, String localName, String qName) throws SAXException
{
//如果解析一个item节点结束,就将rssItem添加到rssFeed中。
if (localName.equals("item"))
{
rssFeed.addItem(rssItem);
return;
}
}
 
public void characters(char ch[], int start, int length)
{
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;
}
}
}
8 主界面Activity代码acc_RssDemo.java
package com.fly.rss;
import java.net.URL;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.AdapterView.OnItemClickListener;
import com.fly.rss.data.*;
import com.fly.rss.data.sax.*;
public class act_RssDemo extends Activity implements OnItemClickListener
{
//我的博客的rss地址
public final String RSS_URL = "http://www.cnblogs.com/flyone/rss";
public final String tag = "RSSReader";
private RSSFeed feed = null;
/** Called when the activity is first created. */
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        feed = getFeed(RSS_URL);
        showListView();  
    }
    //得到rss地址中xml文件的内容进行解析
    private RSSFeed getFeed(String urlString)
    {
    try
    {
      URL url = new URL(urlString);
      //新建一个工厂类
           SAXParserFactory factory = SAXParserFactory.newInstance();
           //工厂类产生出一个sax的解析类
           SAXParser parser = factory.newSAXParser();
           XMLReader xmlreader = parser.getXMLReader();
           
           RSSHandler rssHandler = new RSSHandler();
           xmlreader.setContentHandler(rssHandler);
           InputSource is = new InputSource(url.openStream());    
           xmlreader.parse(is);
           //调用解析的类
           return rssHandler.getFeed();
    }
    catch (Exception ee)
    {
    return null;
    }
    }
    //将解析的xml文件展示出来
    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);
        itemlist.setOnItemClickListener(this);  
        itemlist.setSelection(0);
        
    }
    
    //单击listView时跳转到第二个Activity
     public void onItemClick(AdapterView parent, View v, int position, long id)
     {
    Intent itemintent = new Intent(this,ActivityShowDescription.class);
         
    Bundle b = new Bundle();
    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);
         startActivityForResult(itemintent, 0);
     }
    
}
9 第二个activity代码 ActivityShowDescription
package com.fly.rss;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import android.content.Intent;
import android.view.*;
public class ActivityShowDescription extends Activity {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.showdescription);
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");*/
content = bundle.getString("title") + "\n\n"
+ bundle.getString("pubdate") + "\n\n";
//+ bundle.getString("pubdate") + "\n\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();
}
});
}
}
至此rss阅读器涉及到主要代码就全部完成了,大家可以点击运行了!
上面的简单例子涉及到的知识点有:
(2)sax解析xml文件,详细的介绍:http://blog.csdn.net/shimiso/article/details/5493125
(3)ArrayAdapter的用法,详细的介绍:http://apps.hi.baidu.com/share/detail/30784807
当然还有很多,大家不懂时可以继续google!