[转帖]构建 Android 手机 RSS 阅读器(二)_Android, Python及开发编程讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Android, Python及开发编程讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 2693 | 回复: 0   主题: [转帖]构建 Android 手机 RSS 阅读器(二)        下一篇 
wei.wang
注册用户
等级:少校
经验:1001
发帖:87
精华:0
注册:2013-8-29
状态:离线
发送短消息息给wei.wang 加好友    发送短消息息给wei.wang 发消息
发表于: IP:您无权察看 2013-9-6 10:35:11 | [全部帖] [楼主帖] 楼主

RSSHandler 解释接下来进一步查看一下 RSSHandler 类。注意,该类具有一个 RSSFeed 类的实例。RSSHandler 类的作用是从 SAX 解析器实现回调,并在此过程中形成 RSS 数据的表示以供应用程序使用。startElement 方法指定找到了哪些数据元素,而 characters 方法通过相应的 set 方法向其中一个 RSSItem 成员执行分配。endElement 检查 item 元素的末尾,如果发现数据元素,则将当前的 RSSItem 添加到 RSSFeed。RSSHandler 被设计为自包含形式,以进行 SAX 解析。它的方法都可以响应解析器的事件,构建 RSSFeed,该类随后通过 getFeed 方法使完全填充的 RSSFeed 对象变为可用。设置 SAX现在您大致了解了在进行 SAX 解析时发生的操作,现在查看一下 SAX 解析器的调用。相关的代码位于 RSSFeed 类的 getFeed() 方法中,如清单 7 所示。
清单 7. RSSFeed.java 中的 getFeed() 方法

  1. private RSSFeed getFeed(String urlToRssFeed)
  2. {
  3.       try
  4.       {
  5.             // setup the url
  6.             URL url = new URL(urlToRssFeed);
  7.             
  8.             // create the factory
  9.             SAXParserFactory factory = SAXParserFactory.newInstance();
  10.             // create a parser
  11.             SAXParser parser = factory.newSAXParser();
  12.             
  13.             // create the reader (scanner)
  14.             XMLReader xmlreader = parser.getXMLReader();
  15.             // instantiate our handler
  16.             RSSHandler theRssHandler = new RSSHandler();
  17.             // assign our handler
  18.             xmlreader.setContentHandler(theRssHandler);
  19.             // get our data through the url class
  20.             InputSource is = new InputSource(url.openStream());
  21.             // perform the synchronous parse 
  22.             xmlreader.parse(is);
  23.             // get the results - should be a fully populated RSSFeed instance, 
  24.             // or null on error
  25.             return theRssHandler.getFeed();
  26.       }
  27.       catch (Exception ee)
  28.       {
  29.             // if you have a problem, simply return null
  30.             return null;
  31.       }
  32. }

复制代码



查看 清单 7 中的代码,可以看到,对 SAX 解析器和您的 RSSHandler 类必需的类进行了实例化。当将 RSSHandler 分配给 XMLReader 实例后,就可以开始进行解析。注意,SAX 中最困难的工作就是定义您的处理程序!但是在可以解析数据之前,您必须对数据进行检索。

获取 XML 数据获取 XML 数据流的 HTTP 事务通过 URL 类实现,将它的 Stream 传递给 InputSource 类的新实例。SAX 解析器/扫描器在分配的处理程序内调用各种方法,使用 InputSource 导航数据流并执行解析操作。在本例中,这些方法都位于 RSSHandler 类中。一旦解析完成,将从 RSSHandler 中检索 RSSFeed,RSSHandler 在每次回调操作期间构建一个 RSSFeed 类的实例。try/catch 块中将尝试一个解析操作,如果操作成功,将返回一个 RSSFeed 的实例。如果发生错误,将抛出异常并且函数返回 null。当一个完整的 RSSFeed 类的实例可用后,将开始向用户呈现数据.
在 Android 中呈现 RSS 数据现在,RSS 提要中的 XML 数据安全地保存在内存中 RSSFeed 的实例中,该实例使用一个方便的 List 结构包含了许多 RSSItem。RSS 阅读器的目的就是管理数据并以一种整洁的方式呈现给用户。在这里,Android 用户界面代码和各种资源将进行交互。本节将介绍 Android 用户界面的实现以及显示 RSS 数据的方式。主用户界面RSSReader 应用程序的启动 Activity 是 RSSReader 类。Activity 的入口点是 onCreate 方法。该方法负责启动用户界面,在某些情形下,例如在本例中,除创建用户界面外,它还将发起后续操作。查看 RSSReader.java 中的 onCreate 方法,如清单 8 所示,可以看到应用程序的结构非常简单。
清单 8. The RSSReader 的 onCreate 方法

  1. private RSSFeed feed = null;
  2. public void onCreate(Bundle icicle) {
  3.       super.onCreate(icicle);
  4.       setContentView(R.layout.main);
  5.       
  6.       // go get our feed!
  7.       feed = getFeed(RSSFEEDOFCHOICE);
  8.       
  9.       // display UI
  10.       UpdateDisplay();
  11.       
  12. }

复制代码



onCreate 方法执行以下三个功能:

  • 创建由 R.layout.main 确定的用户界面并呈现 main.xml 中包含的布局。
  • 通过调用 getFeed() 方法创建一个 RSSFeed 类的实例。
  • 通过 UpdateDisplay() 方法��新用户界面以反映 RSS 提要内容。




用户界面布局RSSReader Activity 的用户界面包括两个 TextView 和一个 ListView。TextView 显示通道标题和发布日期,而 ListView 显示 RSSFeed 中的 RSSItems 列表。清单 9 包含了 Activity 主用户界面的布局。
清单 9. main.xml 包含 RSSReader Activity 的用户界面定义

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. >
  7. <TextView 
  8. android:layout_width="fill_parent" 
  9. android:layout_height="wrap_content" 
  10. android:text="Android RSSReader"
  11. android:id="@+id/feedtitle"
  12. />
  13. <TextView 
  14. android:layout_width="fill_parent" 
  15. android:layout_height="wrap_content" 
  16. android:text=""
  17. android:id="@+id/feedpubdate"
  18. />
  19. <ListView
  20. android:layout_width="fill_parent"
  21. android:layout_height="fill_parent"
  22. android:id="@+id/itemlist"
  23. /> 
  24. </LinearLayout>

复制代码



main.xml 中的布局具有非常简单的用户界面视图。注意每个视图中出现的 android:id 属性。这样做是有其意义的,因为应用程序将动态更新每个视图的内容。




呈现查看清单 10 中的 UpdateDisplay 方法,了解 RSSFeed 数据如何连接到用户界面。RSSFeed 类的实例现在包含 RSS 数据。执行UpdateDisplay  方法,获取 RSS 数据并通过 Android 用户界面呈现。
清单 10.UpdateDisplay方法将数据连接到用户界面

  1. private void UpdateDisplay()
  2. {
  3.       TextView feedtitle = (TextView) findViewById(R.id.feedtitle);
  4.       TextView feedpubdate = (TextView) findViewById(R.id.feedpubdate);
  5.       ListView itemlist = (ListView) findViewById(R.id.itemlist);
  6.       
  7.       
  8.       if (feed == null)
  9.       {
  10.             feedtitle.setText("No RSS Feed Available");
  11.             return;
  12.       }
  13.       
  14.       feedtitle.setText(feed.getTitle());
  15.       feedpubdate.setText(feed.getPubDate());
  16.       
  17.       
  18.       ArrayAdapter<RSSItem> adapter = new
  19.       ArrayAdapter<RSSItem>(this,android.R.layout.
  20.       simple_list_item_1,feed.getAllItems());
  21.       
  22.       itemlist.setAdapter(adapter);
  23.       
  24.       itemlist.setSelection(0);
  25.       
  26.       itemlist.setOnItemClickListener(this);
  27.       
  28.       
  29. }

复制代码

查看清单 10,UpdateDisplay 方法通过 findViewById() 方法将两个 TextView 对象和一个 ListView 对象连接到布局,并分别传入标识符。如果 RSSFeed 为 null,该方法将显示一条消息表示 RSS 提要可用。通道标题和发布日期分别使用 TextView 对象显示。
RSSItems 列表要将 RSSItems 列表连接到 ListView,需要创建一个 ArrayAdapter 类的实例。构建这个参数化的类是为了管理 RSSItem 类型的项。列表布局由内置的资源 simple_list_item_1 管理,该内置资源实质上是一个列表,其中每个条目支持一行文本。还需通过 RSSFeed 类的getAllItems() 方法传递 RSSFeed 中的所有 RSSItem 条目的列表。上文提到过,RSSItem 类覆盖了默认的toString() 方法,允许ArrayAdapter 获得有意义的表示以便在 ListView 中显示。清单 11 显示这个方法如何实现相同的格式化以确保文本恰当地嵌入到 ListView 中。
清单 11. 覆盖RSSItem 类的默认的 toString()方法

  1. public String toString()
  2. {
  3.       // limit how much text you display
  4.       if (_title.length() > 42)
  5.       {
  6.             return _title.substring(0, 42) + "...";
  7.       }
  8.       return _title;
  9. }

复制代码

ArrayAdapter 被分配给 ListView,并且通过使用参数 0 调用 setSelection 选择了第一个条目。最后,您需要使用 setOnItemClickListener 方法创建一个侦听器来响应项选择事件。RSSReader 类实现 OnItemClickListener 界面:public class RSSReader extends Activity implements OnItemClickListener。侦听器功能由 onItemClick 方法实现,如清单 12 所示。
清单 12.onItemClick实现

  1. public void onItemClick(AdapterView parent, View v, int position, long id)
  2. {
  3.       Log.i(tag,"item clicked! [" + feed.getItem(position).getTitle() + "]");
  4.       
  5.       Intent itemintent = new Intent(this,ShowDescription.class);
  6.       
  7.       Bundle b = new Bundle();
  8.       b.putString("title", feed.getItem(position).getTitle());
  9.       b.putString("description", feed.getItem(position).getDescription());
  10.       b.putString("link", feed.getItem(position).getLink());
  11.       b.putString("pubdate", feed.getItem(position).getPubDate());
  12.       
  13.       itemintent.putExtra("android.intent.extra.INTENT", b);
  14.       
  15.       startSubActivity(itemintent,0);
  16. }

复制代码

当选择 ListView 的某个项后,应用程序将显示所选的 RSSItem 的 Description 元素。查看 onItemClick 中的代码并注意以下三点:

  • 需要创建 Intent 来启动另一个 Activity,ShowDescription Activity 在 ShowDescription.java 中定义
  • 使用 Bundle 将数据传递给被调用的行为
  • 以子行为(sub activity)的方式启动 ShowDescription 行为,它可帮助应用程序实现同步功能
ShowDescriptionShowDescription Activity 提供了所选 RSSItem 的下一层细节,如图 2 所示。
图 2. 所选RSSItem 的下一层细节

北京联动北方科技有限公司

清单 13 列出了 ShowDescription 类。注意解除绑定 RSSItem 数据以及格式化用于用户界面的字符串的过程。
清单 13.ShowDescription行为

  1. package com.msi.androidrss;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.widget.Button;
  5. import android.widget.TextView;
  6. import android.content.Intent;
  7. import android.view.*;
  8. public class ShowDescription extends Activity 
  9. {
  10.       public void onCreate(Bundle icicle) 
  11.       {
  12.             super.onCreate(icicle);
  13.             setContentView(R.layout.showdescription);
  14.             
  15.             String theStory = null;
  16.             
  17.             
  18.             Intent startingIntent = getIntent();
  19.             
  20.             if (startingIntent != null)
  21.             {
  22.                   Bundle b = startingIntent.getBundleExtra("android.intent.extra.INTENT");
  23.                   if (b == null)
  24.                   {
  25.                         theStory = "bad bundle?";
  26.                   }
  27.                   else
  28.                   {
  29.                         theStory = b.getString("title") + "\n\n" + b.getString("pubdate") 
  30.                         + "\n\n" + b.getString("description").replace('\n',' ') 
  31.                         + "\n\nMore information:\n" + b.getString("link");
  32.                   }
  33.             }
  34.             else
  35.             {
  36.                   theStory = "Information Not Found.";
  37.                   
  38.             }
  39.             
  40.             TextView db= (TextView) findViewById(R.id.storybox);
  41.             db.setText(theStory);
  42.             
  43.             Button backbutton = (Button) findViewById(R.id.back);
  44.             
  45.             backbutton.setOnClickListener(new Button.OnClickListener() 
  46.             {
  47.                   public void onClick(View v) 
  48.                   {
  49.                         finish();
  50.                   }
  51.             }); 
  52.       }
  53. }

复制代码

需要确保 Activity 没有尝试处理一个 null Bundle 或显示错误的数据。确保变量 theStory 始终具有一个有效的值。




back 按钮代码使用一个简单的 Button OnClickListener 终止这个 Activity。由于这个 Activity 使用 startSubActivity() 方法启动,因此调用finish() 将导致控制权返回给调用的 Activity,即RSSReader。注意,描述的文本表示包含一个超链接。Android 通过属性 android:autoLink="all" 自动处理这一点,如清单 14 所示。
清单 14. ShowDescription.xml 定义 ShowDescription Activity 的用户界面

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. >
  7. <TextView 
  8. android:layout_width="fill_parent" 
  9. android:layout_height="wrap_content" 
  10. android:autoLink="all"
  11. android:text="story goes here ...."
  12. android:id="@+id/storybox"
  13. />
  14. <Button
  15. android:layout_width="wrap_content" 
  16. android:layout_height="wrap_content" 
  17. android:text="Back"
  18. android:id="@+id/back"
  19. /> 
  20. </LinearLayout>

复制代码

通过链接文本,使用 RSSItem 链接启动 Web 站点是一个零代码操作,如图 3 和图 4 所示。
图 3. 文本中的 Web 站点引用将自动使用超链接

北京联动北方科技有限公司

图 4 展示了从 RSSItem 链接元素启动的 Web 页面。它演示了 RSS 的强大和高效性。在选择提要项时,将显示感兴趣的主题。您将看到一些简洁的摘要,如果这些内容提供了足够的信息量,那么就可以满足您的需求。如果您希望查看更多的内容,那么可以单击链接,从而获得更详细的信息。
图 4. 启动RSSItem 链接元素中的 Web 页面

北京联动北方科技有限公司

大功告成!您现在拥有了一个可以工作的 RSS 阅读器!



扩展钩子在源代码中,最后要查看的是用于设置菜单的 RSSReader.java 文件。本教程没有解决选择和刷新 RSS 提要的问题,但是,您将看到提供了一些钩子,用于在未来的教程中实现这些功能。清单 15 包含了两个实现菜单行为的方法。
清单 15. 菜单处理方法

  1. public boolean onCreateOptionsMenu(Menu menu) 
  2. {
  3.       super.onCreateOptionsMenu(menu);
  4.       
  5.       menu.add(0,0,"Choose RSS Feed");
  6.       menu.add(0,1,"Refresh");
  7.       Log.i(tag,"onCreateOptionsMenu");
  8.       return true;
  9. }
  10. public boolean onOptionsItemSelected(Menu.Item item){
  11.       switch (item.getId()) {
  12.             case 0:
  13.             
  14.             Log.i(tag,"Set RSS Feed");
  15.             return true;
  16.             case 1:
  17.             Log.i(tag,"Refreshing RSS Feed");
  18.             return true;
  19.       }
  20.       return false;
  21. }

复制代码

在 Activity 生命周期中将调用一次 onCreateOptionsMenu(),它允许创建菜单项。该方法的第二个参数是菜单的惟一标识符。当用户选择某个项时将调用 onOptionsItemSelected 方法。通过getId() 方法���用菜单项的标识符,可以简单地响应特定的菜单选择。对功能进行扩展超出了本教程的讨论范围;这些方法可以作为增强 Android RSS 阅读器的起点!


结束语结束语本教程演示了如何为 Android 构建一个 RSS 阅读器应用程序。通过对 RSS 数据提要结构的讨论,我们发现 SAX 解析方法非常适合 RSS version 2.0 的简单 XML 结构。使用 SAX 处理 XML 数据时,由回调处理程序使用的五种方法保证了解析 RSS 数据的效率。在解析和组织 RSS 数据时,可通过一个定制的视图呈现数据。对于感兴趣的读者,本教程还提供了一些钩子,以便将这个示例应用程序进一步扩展为一个功能更丰富的 RSS 阅读器。



赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论