Android使用XML全攻略(1)

  

Android 是针对移动设备的一种新兴的开源操作系统和 SDK。借助它,您可以创建功能强大的移动应用程序。当您的应用程序可以访问 Web 服务时,其吸引力会大大增加,这意味着您需要使用 Web 语言:XML。在本文中,您将了解在 Android 上使用 XML 的不同方法,以及如何使用它们构建自己的 Android 应用程序。

入门

在本文中,您将学习如何构建通过 Internet 使用 XML 的 Android 应用程序。Android 应用程序是使用 Java™ 编程语言编写的,因此具备 Java 技术方面的经验是必需的。要进行 Android 开发,您需要使用 android sdk。 本文中的所有代码适用于任何版本的 Android SDK,但 SDK 1.5_pre 是用于开发代码的。您可以使用 SDK 和一个文本编辑器来开发 Android 应用程序,但使用Android Developer Tools (ADT)(一款 Eclipse
插件)会更加简单。在本文中,我们使用 0.9 版本的 ADT 和 Eclipse 3.4.2, Java 版本。有关所有这些工具的链接,请参见 参考资料。

Android上的XML

Android 平台是一个开源移动开发平台。它允许您访问各种移动设备的所有方面,这些移动设备从低级图形设备到手机摄像头上的硬件不一而足。由于 Android 可以实现这么丰富的功能,因此您可能想知道为何还要为 XML 伤脑筋呢。并不是因为使用 XML 是多么地有趣;而是因为它能提供一些特殊的支持。XML经常用作 Internet上的一种数据格式。如果您希望通过 Internet 访问数据,则数据很有可能是 XML 格式。如果您希望发送数据给 Web 服务,那么您可能也需要发送 XML。简而言之,如果您的Android应用程序将利用
Internet,那么您可能需要使用 XML。幸运的是,您可以采用多种方法在Android上使用 XML。

XML 解析器常用缩略语

  • API:应用程序编程接口(Application programming interface)
  • RSS:Really Simple Syndication
  • SDK:软件开发包(Software Developers Kit)
  • UI:用户界面(User interface)
  • URL:通用资源定位符(Universal Resource Locator)
  • XML:可扩展标记语言(Extensible Markup Language)

Android 平台最大的一个优势在于它利用了 Java 编程语言。Android SDK 并未向您的标准 Java Runtime Environment (JRE) 提供一切可用功能,但它支持其中很大一部分功能。Java 平台支持通过许多不同的方式来使用 XML,并且大多数与 XML 相关的 Java API 在 Android 上得到了完全支持。举例来说,Java 的 Simple API for XML (SAX) 和 Document Object Model (DOM) 在 Android 上都是可用的。这些
API 多年以来一直都是 Java 技术的一部分。较新的 Streaming API for XML (StAX) 在 Android 中并不可用。但是, Android 提供了一个功能相当的库。最后,Java XML Binding API 在 Android 中也不可用。这个 API 已确定可以在 Android 中实现。但是,它更倾向于是一个重量级的 API,需要使用许多不同类的实例来表示 XML 文档。因此,这对于受限的环境,比如说 Android 针对的手持设备,不太理想。在后续小节中,我们将以
Internet 上的一个简单的 XML 源为例,来看看如何在 Android 应用程序中使用上述各种 API 来解析它。首先,我们来看看这个简单应用程序的主要部分,它将通过 Internet 来使用 XML。

Android 新闻阅读器

应用程序将从热门 Android 开发人员站点 Androidster 获取一个 RSS 提要,并将它解析为一组简单的 Java 对象,您可以使用这些对象构建一个 Android ListView(参见下载部分获取源代码)。这是一种典型的多态行为 — 提供相同行为的不同实现(不同的 XML 解析算法)。清单 1 展示了如何在 Java 代码中使用一个接口建立这一模型。

清单 1. XML 提要解析器接口[size=0.76em]

  1. package org.developerworks.android;
  2. import java.util.List;
  3. public interface FeedParser {
  4. List<Message> parse();
  5. }

在清单2中,Message 类是一个典型的 Plain Old Java Object (POJO),它表示一种数据结构。

清单 2. Message POJO

  1. public class Message implements Comparable<Message>{
  2. static SimpleDateFormat FORMATTER =
  3. new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
  4. private String title;
  5. private URL link;
  6. private String description;
  7. private Date date;
  8. // getters and setters omitted for brevity
  9. public void setLink(String link) {
  10. try {
  11. this.link = new URL(link);
  12. } catch (MalformedURLException e) {
  13. throw new RuntimeException(e);
  14. }
  15. }
  16. public String getDate() {
  17. return FORMATTER.format(this.date);
  18. }
  19. public void setDate(String date) {
  20. // pad the date if necessary
  21. while (!date.endsWith("00")){
  22. date += "0";
  23. }
  24. try {
  25. this.date = FORMATTER.parse(date.trim());
  26. } catch (ParseException e) {
  27. throw new RuntimeException(e);
  28. }
  29. }
  30. @Override
  31. public String toString() {
  32. // omitted for brevity
  33. }
  34. @Override
  35. public int hashCode() {
  36. // omitted for brevity
  37. }
  38. @Override
  39. public boolean equals(Object obj) {
  40. // omitted for brevity
  41. }
  42. // sort by date
  43. public int compareTo(Message another) {
  44. if (another == null) return 1;
  45. // sort descending, most recent first
  46. return another.date.compareTo(date);
  47. }
  48. }

清单 2 中的消息基本上是相当直观的。通过允许日期和链接作为简单的对象被访问,同时将它们表示为较强类型的对象(java.util.Date 和 java.net.URL),它隐藏了一些内部状态。它是一个典型的
Value Object,因此它基于其内部状态实现了equals() 和 hashCode()。它还实现了Comparable 接口,因此您可以使用它进行排序(按日期)。在实践中,提要中的数据始终是有序的,因为没有必要再进行排序。

每个解析器实现都需要提供一个URL给Androidster提要,并使用它打开一个到Androidster站点的HTTP连接。这一常见行为自然是在 Java 代码中建模,我们使用了一个抽象基类,如清单3所示。

清单 3. 基本提要解析器类

  1. public abstract class BaseFeedParser implements FeedParser {
  2. // names of the XML tags
  3. static final String PUB_DATE = "pubDate";
  4. static final String DESCRIPTION = "description";
  5. static final String LINK = "link";
  6. static final String TITLE = "title";
  7. static final String ITEM = "item";
  8. final URL feedUrl;
  9. protected BaseFeedParser(String feedUrl){
  10. try {
  11. this.feedUrl = new URL(feedUrl);
  12. } catch (MalformedURLException e) {
  13. throw new RuntimeException(e);
  14. }
  15. }
  16. protected InputStream getInputStream() {
  17. try {
  18. return feedUrl.openConnection().getInputStream();
  19. } catch (IOException e) {
  20. throw new RuntimeException(e);
  21. }
  22. }
  23. }

基类存储 feedUrl 并使用它打开了一个 java.io.InputStream。如果出现任何差错,它会抛出一个 RuntimeException,造成应用程序出现故障。基类还为标记的名称定义了一些简单的常量。清单 4 显示了提要中的一些示例内容,以便于您理解这些标记的重要性。

清单 4.示例XML提要

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- generator="FeedCreator 1.7.2" -->
  3. <rss version="2.0">
  4. <channel>
  5. <title>android_news</title>
  6. <description>android_news</description>
  7. <link><a href="\"http://www.androidster.com/android_news.php</link>\"" target="\"_blank\"">http://www.androidster.com/android_news.php</link></a>
  8. <lastBuildDate>Sun, 19 Apr 2009 19:43:45 +0100</lastBuildDate>
  9. <generator>FeedCreator 1.7.2</generator>
  10. <item>
  11. <title>Samsung S8000 to Run Android, Play DivX, Take Over the
  12. World</title>
  13. <link><a href="\"http://www.androidster.com/android_news/samsung-s8000-to-run-android-\"" target="\"_blank\"">http://www.androidster.com/andro ... 000-to-run-android-</a>
  14. play-divx-take-over-the-world</link>
  15. <description>More details have emerged on the first Samsung handset
  16. to run Android. A yet-to-be announced phone called the S8000 is being
  17. reported ...</description>
  18. <pubDate>Thu, 16 Apr 2009 07:18:51 +0100</pubDate>
  19. </item>
  20. <item>
  21. <title>Android Cupcake Update on the Horizon</title>
  22. <link><a href="\"http://www.androidster.com/android_news/android-cupcake-update-\"" target="\"_blank\"">http://www.androidster.com/android_news/android-cupcake-update-</a>
  23. on-the-horizon</link>
  24. <description>After months of discovery and hearsay, the Android
  25. build that we have all been waiting for is about to finally make it
  26. out ...</description>
  27. <pubDate>Tue, 14 Apr 2009 04:13:21 +0100</pubDate>
  28. </item>
  29. </channel>
  30. </rss>

如清单4中的示例所示,一个ITEM对应于一个Message实例。项目的子节点(TITLE、LINK 等)对应于 Message 实例的属性。现在,您已经对提要有了一定的认识,并且已经创建了所有常用部分,接下来看看如何使用 Android 上可用的各种技术来解析这个提要。您将从 SAX 开始。

使用 SAX

在Java环境中,当您需要一个速度快的解析器并且希望最大限度减少应用程序的内存占用时,通常可以使用 SAX API。这非常适用于运行 Android 的移动设备。您可以在 Java 环境中照原样使用 SAX API,在 Android 上运行它不需要做任何修改。清单 5 显示了FeedParser 接口的一个 SAX 实现。

清单 5. SAX 实现

  1. public class SaxFeedParser extends BaseFeedParser {
  2. protected SaxFeedParser(String feedUrl){
  3. super(feedUrl);
  4. }
  5. public List<Message> parse() {
  6. SAXParserFactory factory = SAXParserFactory.newInstance();
  7. try {
  8. SAXParser parser = factory.newSAXParser();
  9. RssHandler handler = new RssHandler();
  10. parser.parse(this.getInputStream(), handler);
  11. return handler.getMessages();
  12. } catch (Exception e) {
  13. throw new RuntimeException(e);
  14. }
  15. }
  16. }

如果您以前使用过 SAX,那么这对您肯定非常熟悉。与任何 SAX 实现相同,大多数细节都在 SAX 处理程序中。在分解 XML 文档时,处理程序从 SAX 解析器接收事件。在本例中,您创建了一个新的名称为 RssHandler 的类,并将它注册为解析器的处理程序,如 清单 6 所示。

清单 6. SAX 处理程序

  1. import static org.developerworks.android.BaseFeedParser.*;
  2. public class RssHandler extends DefaultHandler{
  3. private List<Message> messages;
  4. private Message currentMessage;
  5. private StringBuilder builder;
  6. public List<Message> getMessages(){
  7. return this.messages;
  8. }
  9. @Override
  10. public void characters(char[] ch, int start, int length)
  11. throws SAXException {
  12. super.characters(ch, start, length);
  13. builder.append(ch, start, length);
  14. }
  15. @Override
  16. public void endElement(String uri, String localName, String name)
  17. throws SAXException {
  18. super.endElement(uri, localName, name);
  19. if (this.currentMessage != null){
  20. if (localName.equalsIgnoreCase(TITLE)){
  21. currentMessage.setTitle(builder.toString());
  22. } else if (localName.equalsIgnoreCase(LINK)){
  23. currentMessage.setLink(builder.toString());
  24. } else if (localName.equalsIgnoreCase(DESCRIPTION)){
  25. currentMessage.setDescription(builder.toString());
  26. } else if (localName.equalsIgnoreCase(PUB_DATE)){
  27. currentMessage.setDate(builder.toString());
  28. } else if (localName.equalsIgnoreCase(ITEM)){
  29. messages.add(currentMessage);
  30. }
  31. builder.setLength(0);
  32. }
  33. }
  34. @Override
  35. public void startDocument() throws SAXException {
  36. super.startDocument();
  37. messages = new ArrayList<Message>();
  38. builder = new StringBuilder();
  39. }
  40. @Override
  41. public void startElement(String uri, String localName, String name,
  42. Attributes attributes) throws SAXException {
  43. super.startElement(uri, localName, name, attributes);
  44. if (localName.equalsIgnoreCase(ITEM)){
  45. this.currentMessage = new Message();
  46. }
  47. }
  48. }

RssHandler 类扩展了 org.xml.sax.helpers.DefaultHandler 类。该类为 SAX 解析器生成的事件所对应的所有方法都提供了一个默认的非操作实现。这允许子类根据需要仅覆盖一些方法。RssHandler 提供了一个额外的 API,即 getMessages。它返回处理程序在从 SAX 解析器接收事件时所收集的 Message 对象列表。它有另外两个内部变量,currentMessage 针对被解析的 Message 实例,以及名称为 builder 的 StringBuilder
变量,用于存储文本节点中的字符数据。解析器将相应事件发送给处理程序时会调用 startDocument 方法,这两个变量的初始化操作就是在此时完成。

查看清单6中的startElement方法。在XML文档中每次遇到开始标记时都会调用它。您只关心该标记何时为ITEM标记。对于这种情况,您将创建一个新的Message。现在来看characters方法。遇到文本节点中的字符数据时便会调用此方法。数据只是被添加到builder变量中。最后,我们来看endElement方法。遇到结束标记时会调用此方法。对于与某Message属性相对应的标记,如TITLE和LINK,则使用builder变量中的数据在currentMessage上设置适当的属性。如果结束标记是一个ITEM,则currentMessage将被添加到Messages列表中。所有这些都是非常典型的SAX解析;此处的一切都不是Android所特有的。因此,如果您知道如何编写Java
SAX解析器,则应该知道如何编写Android SAX解析器。但是,Android SDK确实在SAX上添加了一些便捷的特性。

Android使用XML全攻略(1)的更多相关文章

  1. Android使用XML全攻略(2)

    Android使用XML全攻略(2)   Android 是针对移动设备的一种新兴的开源操作系统和 SDK.借助它,您可以创建功能强大的移动应用程序.当您的应用程序可以访问 Web 服务时,其吸引力会 ...

  2. Android屏幕适配全攻略(最权威的官方适配指导)屏幕尺寸 屏幕分辨率 屏幕像素密度 dpdipdpisppx mdpihdpixdpixxdpi

    Android屏幕适配全攻略(最权威的官方适配指导)原创赵凯强 发布于2015-05-19 11:34:17 阅读数 153734 收藏展开 转载请注明出处:http://blog.csdn.net/ ...

  3. Android屏幕适配全攻略 (转载)

    http://blog.csdn.net/jdsjlzx/article/details/45891551 https://github.com/hongyangAndroid/AndroidAuto ...

  4. 【收藏】Android屏幕适配全攻略(最权威的Google官方适配指导)

    来源:http://blog.csdn.net/zhaokaiqiang1992 更多:Android AutoLayout全新的适配方式, 堪称适配终结者 Android的屏幕适配一直以来都在折磨着 ...

  5. Android屏幕适配全攻略(最权威的官方适配指导)(转),共大家分享。

    Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了Android屏幕适配的原因.重要概念.解决方案及最佳实践,我相信如果你能认真的学习 ...

  6. Android屏幕适配全攻略(最权威的官方适配指导) (转)

    招聘信息: Cocos2d-X 前端主程 [新浪微博]手机客户端iOS研发工程师 20k-40k iOS 开发工程师 iOS高级开发工程师(中国排名第一的企业级移动互联网云计算公司 和创科技 红圈营销 ...

  7. 【转】Android屏幕适配全攻略(最权威的官方适配指导)

    原文网址:http://blog.csdn.net/jdsjlzx/article/details/45891551 Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的 ...

  8. Android屏幕适配全攻略(最权威的官方适配指导)

    转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入 ...

  9. Android屏幕适配全攻略(最权威的官方适配指导)

    摘自:http://www.cocoachina.com/android/20151030/13971.html Android屏幕适配出现的原因 在我们学习如何进行屏幕适配之前,我们需要先了解下为什 ...

随机推荐

  1. C语言学习——C程序的运行机理

    预处理: #include<xxx> 尖括号表示库文件:#include"xxx" 双引号表示自己写的文件. #include后面的文件格式允许多种,但若要是" ...

  2. 文本域textarea显示输入剩余字数

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. Eric6 右键点击生产对话框代码报错

    问题没有解决,属于菜鸟级别的孩子~~~~ 求助啊,求助!!!!!! 报告如下: Warning:An unhandled exception occurred. Please report the p ...

  4. ASP.NET Identity 系列笔记目录

    编写目的 混迹博客园已经有一段时间了,一直都是在学习各路大神的文章,自己却没有做出什么贡献,所以觉得应该写一点点内容和大家一起分享.但是本人实在才疏学浅,有心无力啊!正好最近在学习 Microsoft ...

  5. FAQ:Python 断点调试

    Python程序调试:断点调试是必须有的功能,以Pycharm开发工具为例: 一.理论知识: 1. step into(F7)就是单步执行,遇到子函数就进入并且继续单步执行: 2  step over ...

  6. 蓝牙1.1、蓝牙1.2、蓝牙2.0(蓝牙2.0+EDR)区别

    蓝牙1.2版本相对于1.1版本: 1.Adaptive Frequency Hopping(AFH):即所谓适应性跳频技术,主要的功能是用来减少蓝牙产品与其它无线通讯装置之间所产生的干扰问题 2.Ex ...

  7. [原]容器学习(一):动手模拟spring的IoC

    介绍 学习经典框架的实现原理以及设计模式在其实际中的运用,是非常有必要的,可以让我们更好进行面向对象. 本篇文章就来模拟Spring的IOC功能,明白原理后,可以更好的使用它,进而为进行面向对象提供一 ...

  8. C语言数据结构----栈的应用(程序的符号匹配检测)

    本节主要讲利用栈来实现一个程序中的成对出现的符号的检测,完成一个类似编译器的符号检测的功能,采用的是链式栈. 一.问题的提出以及解决方法 1.假定有下面一段程序: #include <stdio ...

  9. 前端web应用的组件化(二) 徐飞

    Web应用的组件化(二) https://github.com/xufei/blog/issues/7 管控平台 在上一篇中我们提到了组件化的大致思路,这一篇主要讲述在这么做之后,我们需要哪些外围手段 ...

  10. as3用鼠标拖动图形拼图——灰常简单的教程

    话说这种效果在课件里面经常用到,鼠标拖动事件,一个运用很频繁的事件,一起学习学习吧 首先SWF贡献给大家看看效果 感觉咋样,原理其实还蛮简单的,做做试试吧 下面来看看源码吧 package { imp ...