首先需要分析网易RSS订阅中心的网页布局情况。
网易RSS订阅中心:http://www.163.com/rss/
你会发现RSS文件由一个<channel>元素及其子元素组成,除了频道本身内容之外,<channel>还以项的形式包含表示频道元数据的元素。
其中频道下面主要的三个元素就是:
1.title:频道或提要的名称。
2.link:与该频道关联的WEB站点或者站点区域的URL。
3.description:简要介绍该频道是做什么的。
当然还有其他子元素是可选的,比如常用的有<image>,<language>,<copyright><pubDate>等.
下面我们编写的RSS阅读器是包含了四个元素,有titile,link,description,pubDate.
首先:我们创建新闻的实体类:
package com.example.rssview; public class News { private String title;//新闻标题 private String link;//新闻网址 private String description;//新闻描述 private String pubDate;//新闻发布时间 public News() { } public News(String title, String link, String description, String pubDate) { this.title = title; this.link = link; this.description = description; this.pubDate = pubDate; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getPubDate() { return pubDate; } public void setPubDate(String pubDate) { this.pubDate = pubDate; } }
上面是程序开发的第一步,完成实体类的创建
第二步:我们应该也可想而知,必须解析XML的有用数据,常用的解析XML的方法有三种:DOM解析,SAX解析,PULL解析
因为DOM解析必须读取所有的XML内容到内存里面,挺耗系统资源的所以,我推荐选择SAX解析,或者PULL解析。
这里我选择SAX解析方法具体代码如下:
package com.example.rssview; import java.util.ArrayList; import java.util.List; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import android.util.Log; public class SAXParserHelper extends DefaultHandler { private List<News> newsList;//保存解析的所有新闻数据 private News news;//单个新闻内容 private String nodeName;//判断是那个元素用 //获取所有新闻数据 public List<News> getNewsList() { return newsList; } //开始解析XML文档 @Override public void startDocument() throws SAXException { newsList = new ArrayList<News>(); } //结束解析XML文档 @Override public void endDocument() throws SAXException { // TODO Auto-generated method stub super.endDocument(); } //开始解析某个元素 @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (localName.equals("title")) { news = new News(); } this.nodeName = localName; } //结束解析某个元素 @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (localName.equals("item")) { newsList.add(news); // Log.i("SAXParserHelper", news.getTitle()); // Log.i("SAXParserHelper", news.getLink()); // Log.i("SAXParserHelper", news.getPubDate()); // Log.i("SAXParserHelper", news.getDescription()); } } //解析元素的文本内容 @Override public void characters(char[] ch, int start, int length) throws SAXException { if ("title".equals(this.nodeName)) { news.setTitle(String.valueOf(ch, start, length)); } else if ("link".equals(this.nodeName)) { news.setLink(String.valueOf(ch, start, length)); } else if ("description".equals(this.nodeName)) { news.setDescription(String.valueOf(ch, start, length)); } else if ("pubDate".equals(this.nodeName)) { news.setPubDate(String.valueOf(ch, start, length)); } } }
代码就不用多解释了,相信备注已经些的非常的详细了,也提供了供外部获取解析数据的方法getNewsList();
第三步:当然是去Activity活动里面去编写主要的代码了
开始我们必须准备包含了listView控件的布局文件,然后在activity里面设置布局文件
当然你也可以直接继承ListActivity类,这样更方便编程
你也应该知道这是从网络读取网址获取XML数据,根据Android的编程原则,耗时的网络操作不应该在主线程中直接执行,因为这样会造成主线程的崩溃。
然而android给我们提供了一个异步处理的机制类AsyncTask只要自己写个类实现该类把耗时的任务放在doInBackground方法里面处理就可以了。
当我们获得网络数据后就会操作更新UI来显示解析的XML数据,这个时候就可以在AsyncTask的onPostExecute里面解决.
也许我们还应该分析一下AsyncTask的三个参数,第一个参数是传递进来的参数,比如我们下面会传入一个网址供AsyncTask解析获得XML数据,第二个参数就是进度显示单位我们常常设置为Integer,第三个参数就是doInBackground方法返回的数据供onPostExecute调用的数据,也就是onPostExecute的参数.
下面我们首先必须获得网络的XML。
URL url = null;//创建URL对象 String XmlSourceStr = null;//解析后的XML数据 try { url = new URL(params[0]);//获取传递进来的网址资源 if (url != null) { HttpURLConnection conn = (HttpURLConnection) url .openConnection();//打开链接 InputStreamReader isReader = new InputStreamReader( conn.getInputStream(), "UTF-8");//读取数据到InputStreamReader对象中,并设置编码格式为UTF-8 BufferedReader br = new BufferedReader(isReader);//实例化bufferedReader StringBuilder sb = new StringBuilder(); String line = null; while ((line = br.readLine()) != null) { sb.append(line);//读取XML数据到StringBuilder中 } isReader.close();//关闭数据流 conn.disconnect();//关闭连接 XmlSourceStr = sb.toString();//读取StringBuilder数据到字符串中 } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return XmlSourceStr;//返回解析的XML字符串数据
这个方法属于网络处理比较耗时,相信大家也就知道,应该写在doInBackground中
获取网络的XML数据后,下面就是解析XML的数据,上面已经提到过。我们使用的解析方式是SAX解析。代码如下:
SAXParserFactory factory = SAXParserFactory.newInstance();//创建SAXParserFactory实例 if (result != null) { try { SAXParser parser = factory.newSAXParser();//新建SAXParser解析类 XMLReader xmlReader = parser.getXMLReader();//创建XMLReader读取类 SAXParserHelper helper = new SAXParserHelper();//实例化SAX解析方法 xmlReader.setContentHandler(helper);//设置处理器 xmlReader.parse(new InputSource(new StringReader(result)));//读取需要处理的数据 newsList = helper.getNewsList();//获得处理的结果 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
上面的操作不属于网络因为灯会需要操作更新UI,所以代码写在onPostExecute中
下面我们用迭代器遍历处理的结果,当然需要判断获取了需要的结果没有,代码如下:
if (!newsList.isEmpty()) Iterator<News> it = newsList.iterator();
然后创建一个用于接受遍历结果的Map类 Map<String,Object> map=new HashMap<String,Object>();
而simpleAdapter的构造方法中接收的是一个List对象,而上面获取的每个map,也就只是单独的一个新闻,所以必须创建List<Map<String,Object>> newsList=new ArrayList<Map<String,Object>>();将每一条map新闻保存在newsList当中.
对于刚才说的simpleAdapter一般有一点android基础的应该都不陌生,没错他就是简单的适配器.等会将数据显示到listView上面可少不了他。
现在我们就来设置listView显示新闻,代码如下:
首先绑定listView界面
SimpleAdapter adapter=new SimpleAdapter(Context,list对象,布局文件,listView中数据项,listView中数据项对应的ID);
第一个参数并不陌生就是上下文了,简单说就是继承活动的类名.this。
第二个参数属于刚才获取所有新闻的newsList.
第三个参数就是listView要显示的布局文件样式R.layout.你的布局文件名.
第四个参数就是map.put方法中前面字符串的名称.
第五个参数就是第三个参数布局文件中用于显示新闻每个项的ID;
最后设置到listView中就可以了,具体代码如下:
if (!newsList.isEmpty()) { Iterator<News> it = newsList.iterator(); while (it.hasNext()) { News news = (News) it.next(); HashMap<String, Object> map = new HashMap<String, Object>(); map.put("title", news.getTitle()); map.put("pubDate", news.getPubDate()); Log.i("MainActivity", news.getTitle()); Log.i("MainActivity", news.getPubDate()); mData.add(map); } SimpleAdapter adapter = new SimpleAdapter(MainActivity.this, mData, R.layout.list_item, new String[] { "title", "pubDate" }, new int[] { R.id.title, R.id.pubDate }); newsListView.setAdapter(adapter); }
当然这里我并没有做显示新闻详细的内容显示功能,不过相信看懂上面的代码后,你们也知道设置显示新闻相信内容和获取上面的代码有异曲同工之妙了。
好了,简单的RSS阅读器就讲到这样。我的第一篇博文,虽然不尽完美,但也算是讲解程序的一个起点。