Android使用XML全攻略(1)

Android使用XML全攻略(1)

  

Android 是針對移動設備的一種新興的開源操做系統和 SDK。藉助它,您能夠建立功能強大的移動應用程序。當您的應用程序能夠訪問 Web 服務時,其吸引力會大大增長,這意味着您須要使用 Web 語言:XML。在本文中,您將瞭解在 Android 上使用 XML 的不一樣方法,以及如何使用它們構建本身的 Android 應用程序。php

 

入門java

在本文中,您將學習如何構建經過 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

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。app

Android 新聞閱讀器編程語言

應用程序將從熱門 Android 開發人員站點 Androidster 獲取一個 RSS 提要,並將它解析爲一組簡單的 Java 對象,您可使用這些對象構建一個 Android ListView(參見下載部分獲取源代碼)。這是一種典型的多態行爲 — 提供相同行爲的不一樣實現(不一樣的 XML 解析算法)。清單 1 展現瞭如何在 Java 代碼中使用一個接口創建這一模型。編輯器

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

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

在清單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. public String getDate() { 
  15. return FORMATTER.format(this.date); 
  16. public void setDate(String date) { 
  17. // pad the date if necessary 
  18. while (!date.endsWith("00")){ 
  19. date += "0"
  20. try { 
  21. this.date = FORMATTER.parse(date.trim()); 
  22. catch (ParseException e) { 
  23. throw new RuntimeException(e); 
  24. @Override 
  25. public String toString() { 
  26. // omitted for brevity 
  27. @Override 
  28. public int hashCode() { 
  29. // omitted for brevity 
  30. @Override 
  31. public boolean equals(Object obj) { 
  32. // omitted for brevity 
  33. // sort by date 
  34. public int compareTo(Message another) { 
  35. if (another == nullreturn 1
  36. // sort descending, most recent first 
  37. return another.date.compareTo(date); 

清單 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. protected InputStream getInputStream() { 
  15. try { 
  16. return feedUrl.openConnection().getInputStream(); 
  17. catch (IOException e) { 
  18. throw new RuntimeException(e); 

基類存儲 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. public List<Message> parse() { 
  5. SAXParserFactory factory = SAXParserFactory.newInstance(); 
  6. try { 
  7. SAXParser parser = factory.newSAXParser(); 
  8. RssHandler handler = new RssHandler(); 
  9. parser.parse(this.getInputStream(), handler); 
  10. return handler.getMessages(); 
  11. catch (Exception e) { 
  12. throw new RuntimeException(e); 

若是您之前使用過 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. @Override 
  9. public void characters(char[] ch, int start, int length) 
  10. throws SAXException { 
  11. super.characters(ch, start, length); 
  12. builder.append(ch, start, length); 
  13. @Override 
  14. public void endElement(String uri, String localName, String name) 
  15. throws SAXException { 
  16. super.endElement(uri, localName, name); 
  17. if (this.currentMessage != null){ 
  18. if (localName.equalsIgnoreCase(TITLE)){ 
  19. currentMessage.setTitle(builder.toString()); 
  20. else if (localName.equalsIgnoreCase(LINK)){ 
  21. currentMessage.setLink(builder.toString()); 
  22. else if (localName.equalsIgnoreCase(DESCRIPTION)){ 
  23. currentMessage.setDescription(builder.toString()); 
  24. else if (localName.equalsIgnoreCase(PUB_DATE)){ 
  25. currentMessage.setDate(builder.toString()); 
  26. else if (localName.equalsIgnoreCase(ITEM)){ 
  27. messages.add(currentMessage); 
  28. builder.setLength(0); 
  29. @Override 
  30. public void startDocument() throws SAXException { 
  31. super.startDocument(); 
  32. messages = new ArrayList<Message>(); 
  33. builder = new StringBuilder(); 
  34. @Override 
  35. public void startElement(String uri, String localName, String name, 
  36. Attributes attributes) throws SAXException { 
  37. super.startElement(uri, localName, name, attributes); 
  38. if (localName.equalsIgnoreCase(ITEM)){ 
  39. this.currentMessage = new Message(); 

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上添加了一些便捷的特性。

相關文章
相關標籤/搜索