移动设备和平台吹嘘每个新版本都有更多特性和功能,并且仅仅数月重要通告就从主流移动设备提供商中分离出来了。标题多数是关于 UI 特性(例如先进的多点触摸功能和 Adobe? Flash? 技术)以及硬件提升(例如,处理器速度和存储容量)。但是至关重要的仍然是 “内容为王”。内容 ― 或者,一般来说,是数据 ― 在应用程序、服务器、移动设备和用户之间不停地被交换。智能手机,如 Apple 的 iPhone 和 Google 的 Android 只是标价过高且表现不佳的移动电话,而且也不能很好的工作 。
考虑到社会网络非比寻常的成功,例如:Facebook、LinkedIn 和 Twitter。单从特征和功能的角度来说,这些平台很大程度上都是单调的,之所以流行是因为会员和网站访问者可以从其公布的内容获益。而且,其内容逐渐可以通过移动设备访问。
这篇文章主要说明 Android 平台上 XML 和 JSON 数据交换格式的使用。对于一个 Twitter 帐户,示例应用程序数据源是一个状态更新 feed。Feed 数据可以以 XML 和 JSON 格式从 Twitter 上获取。正如您所看到的,操作数据的程序设计方法在这两种格式中明显不同。
建议您安装 Android SDK version 1.5 或最新版以及 Eclipse 来运行本文附带的?示例代码。为了了解更多关于设置环境的知识,访问 Android Developers 网站。使用一个活动的帐户跟着示例练习是很重要的,但不是必须的。相关链接见?参考资料。
首先我们来简要的看一下这两个数据格式,从 XML 开始。如果您对 XML 和 JSON 已经很熟悉了,就可以跳转到?应用机会:Twitter feeds?在 Android 上开始运行。
XML:一个老朋友
事实上,近几年来为企业、web 或移动市场编程的人都遇到过 XML,几乎您见到的每个地方都有。
一个 XML 文档有一个可辨认的结构:一系列可以随意包含属性和子元素的元素。每个有效的 XML 文件第一行都有这样一个声明:<?xml version="1.0" encoding="utf-8"?>
。后面的内容根据应用程序而定。XML 的好处就在于它的自述性。
XML 模式
尽管 XML 文档是自述的,但也必须遵循一定的规则和指导方针,这就需要 XML 模式,它是一个描述特定 XML 文件结构的文档。此类结构通常是冗长且复杂的。(值得争议的是,XML 对 IT 领域最糟糕的贡献是,当高度描述的数据结构这一理念成为时尚时导致了数据爆炸,且这种情况由于过去十年中磁盘存储技术成本大幅降低而加剧。)
当这些大且复杂的文件变得更规范时,对程序员和分析员来说手工处理通常是不可能完成的。为了解决这个问题,XML 编辑器和验证工具可以在文件和相关的任务管理方面给予帮助。例如,文档和遗留格式转换。
除了一般的文本数据,XML 过去常用于存储二进制数据,通过一个称为?CDATA
?的特殊标记集合实现。一个 XML 文档中的?CDATA
?标记可能含有各种数据,包括其他标记文本,假设该文本本身不含有?CDATA
。
通过使用 XML 作为一个结构来执行请求/响应查询,这并不是 API 使用该功能的常用方式。响应数据经常包含一个包含在?CDATA
?标记中的 XML 结构。例如,一个 API 调用可能使用一个姓氏?Mott
?来请求一个客户记录。数据找到时,封装到一个 XML 结构中并将其置于响应元素中,如?清单 1?所示:
清单 1. 将数据封装到 XML 结构中并将其置于响应元素中?
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <request> <query> <lastname>Mott</lastname> <maxhits>100</maxhits> </query> </request> <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <response> <returncode>200</returncode> <query> <lastname>Mott</lastname> <hits>1</hits> </query> <data> <![CDATA[ <contact> <firstname>Troy</firstname> <lastname>Mott</lastname> <age>not telling</age> </contact> ]]> </data> </response> |
?
工作空间中的 XML
今天,XML 是默认的、预定数据格式。尽管同一数据的其他格式也可用,但基于 XML 结构的可用性进行计划是一种最安全的方式。
Enterprise Resource Planning (ERP) 包频繁使用 XML 进行数据到任务的导入和导出。Internet 新闻网站经常将数据提供为 Really Simple Syndication (RSS) ― 具有新闻阅读软件可以处理的预定义格式的 XML 文档。甚至文字处理应用程序(例如 OpenOffice.org 和 Microsoft? Office)也使用 XML。
现在的 Microsoft Office 文件是 PKZIP 兼容的,含有多个 XML 文档。 每个 XML 在第一行都有这个常见声明。正如您在?清单 2?所看到的,阅读这些属性可能有点难:
清单 2. 每个文件第一行的常见声明
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <w:document xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"> <w:body><w:p w:rsidR="00B6337C" w:rsidRDefault="00663F0E"><w:r> <w:t xml:space="preserve">This is a sample </w:t></w:r><w:r w:rsidRPr="006906EA"><w:rPr><w:i/></w:rPr><w:t>Microsoft Word document</w:t></w:r><w:r><w:t xml:space="preserve"> used to </w:t></w:r><w:r w:rsidRPr="006906EA"><w:rPr><w:b/> <w:u w:val="single"/></w:rPr><w:t>demonstrate</w:t></w:r> <w:r><w:t xml:space="preserve"> some XML topics.</w:t></w:r> </w:p><w:p w:rsidR="00B14B2A" w:rsidRDefault="00B14B2A"/><w:p w:rsidR="00B14B2A"w:rsidRDefault="00B14B2A"><w:r><w:rPr> <w:noProof/></w:rPr><w:drawing><wp:inline distT="0" distB="0" distL="0" distR="0"><wp:extent cx="3276600" cy="3838575"/><wp:effectExtent l="19050" t="0" r="0" b="0"/><wp:docPr id="1" name="Picture 0" descr="frankableson.jpg"/><wp:cNvGraphicFramePr><a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1"/></wp:cNvGraphicFramePr><a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"> <pic:nvPicPr><pic:cNvPrid="0"name="frankableson.jpg"/><pic:cNvPicPr/> </pic:nvPicPr><pic:blipFill><a:blip r:embed="rId4" cstate="print"/><a:stretch><a:fillRect/></a:stretch> </pic:blipFill><pic:spPr><a:xfrm><a:off x="0" y="0"/> <a:ext cx="3276600" cy="3838575"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic> </a:graphicData></a:graphic></wp:inline></w:drawing> </w:r></w:p><w:p w:rsidR="00663F0E" w:rsidRDefault="00663F0E"/> <w:p w:rsidR="00CC16CE" w:rsidRDefault="00CC16CE"/><w:sectPr w:rsidR="00CC16CE" w:rsidSect="00B6337C"><w:pgSz w:w="12240" w:h="15840"/> <w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720" w:gutter="0"/><w:cols w:space="720"/><w:docGrid w:linePitch="360"/></w:sectPr></w:body></w:document> |
?
XML 是自述的,但是并不意味着标记一定是容易理解的。这个虚构的示例展示了多个名称空间的使用,多个名称使得理解 XML 文件更有挑战性,如果不使用专用工具就很难理解。
XML 随处可见,但是对于 Android 程序员来说并不是一个明智的选择,特别是,如果数据结构成为与 XML 结构伴随着的数据爆炸的牺牲品。像 Android 这样通常在蜂窝数据网络(cellular data network)上工作的资源受限平台不能存储和解析大量 XML 数据。然而,如果特殊编程任务要求文本和二进制数据交换,那么 XML 是一个可靠的选择。
现在,让我们看一看数据交换的另一个格式:JSON。
回页首
JSON:网络的新成员
越来越多的 Internet API 供应商提供 JSON 作为一种数据格式。JSON 在 Ajax (Asynchronous JavaScript and XML) 网页编程社区中享有盛名。Ajax 技术使 web 页面可以动态地更新,只更新所选区域的数据而不用更新整个页面。由于较少数据被传送 ― 更重要的是,因为较少的数据被解析且显示在浏览器窗口 ― 使用 AJAX 的应用程序比起传统 web 应用程序能够提供一个更好的用户体验。事实上,一个结构良好的 Ajax 应用程序可与智能或富客户端应用程序相抗衡。
当 Ajax 应用程序与 web 服务器交换数据时,经常需要某类数据的刷新,但不需要格式化。通常认为一个 web 服务器提供预格式化(preformatted)HTML 是一个糟糕的实践。相反的,一个格式良好的应用程序应该将数据内容发送到浏览器并应用一个 Cascading Style Sheets (CSS) 文件来产生视觉效果,比如颜色和特殊字体。
假设应用程序想要请求 Mr. Mott.(这是我们虚构的)的联系记录,应用程序返回浏览器的数据元素不止一个。它是如何包装的呢?在清单 1?示例中,您可以使用一个简单的请求/响应结构。这已经足够了;然而它要求您解析来自服务器的每个响应、以某种结构(DOM)存储数据,然后更新网页内容。
还有一种选择,您可以从服务器上返回一些 JavaScript,并用它来直接处理。以下是一个虚拟应用程序的样例响应,对 Mott 查询(http://<yourserver/app/searchcontact?Mott
)的响应。这个响应是一个 JavaScript 对象字符串表示 ― 即 JSON 字符串(为了适应本文页宽在这分成两行):
[{"firstname":"Troy","lastname":"Mott","age":"don't ask!"},{"firstname":"Apple seed", "lastname":"Mott's","age":"99"}] |
?
XML 以其冗长而著名,而 JSON 也因其难度而闻名。JSON 对象其构造是一个键?:值?对,对象元素之间用逗号隔开,每个对象被包含在一对大括号?{}
?内。一组对象数组包含在一对方括号中。这是将数据行从一个数据库发送到一个对象数组的一种常见方法。其中每个数组元素对应数据库中的一行,每个对象属性代表数据的一列。
清单 3?显示了一个在 HTML 页面中使用这类对象的示例。为简单起见,不包括服务器通信;相反,JSON 数据作为一个字符串变量serverresponse
?提供。
清单 3. 在 HTML 页面中使用一个 JSON 对象
<html> <head> <script language="JavaScript"> var serverresponse = "[{\"firstname\":\"Troy\",\"lastname\":\"Mott\",\"age\":\"don't ask!\"},{\"firstname\":\"Apple seed\",\"lastname\":\"Mott's\",\"age\":\"99\"}]"; function updatepage() { var contacts = eval(serverresponse ); var i; var s = "Search Results:<br />"; for (i=0;i<contacts.length;i++) { s = s + contacts[i].firstname + " " + contacts[i].lastname + "'s age is ... " + contacts[i].age + "<br />"; } document.getElementById("target").innerHTML = s; } </script> </head> <body> <button onclick="updatepage();">Search for Mott</button><br /> <span id="target"> </span> </body> </html> |
?
注意,这个示例使用 JavaScript 函数?eval()
?将字符串转换成一个 JavaScript 数组。JSON 库可以为执行该步骤提供更快更安全的方法,清单 3?中的方法并不是最佳实践。在这只是提供了一个 JSON 对象,如何用于 Ajax 应用程序的背景:JSON 结构可被客户端代码交换、解析和操作。
总的来说,JSON 是:
- 一种数据交换格式。
- JavaScript 对象作为字符串编码的一种方式。
- 仅限于文本和数值。二进制值是明确不允许的。JSON 没有?
CDATA
?对应模式。 - 在数据可读性费用方面、就数据大小而言比 XML 更经济。
- 越来越多的 API 供应商将其作为一种选择,例如 Twitter。
在?清单 3?中,客户端是一个运行客户端脚本的 web 浏览器。返回本文主题,接下来将研究在 Android 应用程序中 XML 和 JSON 的使用。
?
应用机会:Twitter feeds
Twitter 现在已经变成了一种国际力量,它提供的更新包罗万象:从什么人正在吃早饭,他们的孩子的球队在棒球比赛中的表现这类琐事,到封闭国家中的政治动 乱的街头新闻,器官移植实时报道等严肃话题。
要获取一些 XML 和 JSON 文档以用于本文附带的?样例代码,最简单的方法就是通过 URL http://twitter.com/statuses/user_timeline/userid.format,其中?userid?是您的 Twitter 用户 ID,format?是您要的格式:XML 或 JSON。
您也可以直接在您的 Twitte 页面上找到此页的链接,如?图 1?所示。在那里可以看到您的 Twitter 用户 ID。
图 1. 您 Twitter 页面上的 feed 页链接
完整的 feed 文件相当冗长,下面两个清单只显示 feed 的第一项(来自我的 Twitter 帐户)。清单 4?包含以下 XML 片段:
清单 4. XML 片段
<?xml version="1.0" encoding="UTF-8"?> <statuses type="array"> <status> <created_at>Thu Apr 29 05:25:29 +0000 2010</created_at> <id>13052369631</id> <text>Wrapping up new article on JSON for Android programmers...</text> <source><a href="http://www.linkedin.com/"rel="nofollow"> LinkedIn</a></source> <truncated>false</truncated> <in_reply_to_status_id/> <in_reply_to_user_id/> <favorited>false</favorited> <in_reply_to_screen_name/> <user> <id>15221439</id> <name>fableson</name> <screen_name>fableson</screen_name> <location>Byram Township, NJ</location> <description/> <profile_image_url>http://a3.twimg.com/profile_images/260492935 /bookcover_normal.jpg</profile_image_url> <url>http://msiservices.com</url> <protected>false</protected> <followers_count>52</followers_count> <profile_background_color>9ae4e8 <profile_text_color>000000</profile_text_color> <profile_link_color>0000ff</profile_link_color> <profile_sidebar_fill_color>e0ff92 </profile_sidebar_fill_color> <profile_sidebar_border_color>87bc44 </profile_sidebar_border_color> <friends_count>10</friends_count> <created_at>Tue Jun 24 17:04:11 +0000 2008</created_at> <favourites_count>0</favourites_count> <utc_offset>-18000</utc_offset> <time_zone>Eastern Time (US & Canada)</time_zone> <profile_background_image_url>http://s.twimg.com/a/1272044617/ images/themes/theme1/bg.png</profile_background_image_url> <profile_background_tile>false</profile_background_tile> <notifications>false</notifications> <geo_enabled>false</geo_enabled> <verified>false</verified> <following>false</following> <statuses_count>91</statuses_count> <lang>en</lang> <contributors_enabled>false</contributors_enabled> </user> <geo/> <coordinates/> <place/> <contributors/> </status> </statuses> |
?
清单 5?是同一数据,这次是以 JSON 格式显示:
清单 5. JSON 格式的 feed 数据
[ {"in_reply_to_status_id":null, "favorited":false, "created_at":"Thu Apr 29 05:25:29 +0000 2010", "in_reply_to_screen_name":null, "geo":null, "source":"<a href=\"http://www.linkedin.com/\" rel=\"nofollow\ ">LinkedIn</a>", "contributors":null, "place":null, "truncated":false, "coordinates":null, "user": { "friends_count":10, "description":"", "lang":"en", "statuses_count":91, "time_zone":"Eastern Time (US & Canada)", "profile_link_color":"0000ff", "favourites_count":0, "created_at":"Tue Jun 24 17:04:11 +0000 2008", "contributors_enabled":false, "profile_sidebar_fill_color":"e0ff92", "following":null, "geo_enabled":false, "profile_background_image_url":"http://s.twimg.com/a/1272044617/images/themes /theme1/bg.png", "profile_image_url":"http://a3.twimg.com/profile_images/260492935 /bookcover_normal.jpg", "notifications":null, "profile_sidebar_border_color":"87bc44", "url":"http://msiservices.com", "verified":false, "profile_background_tile":false, "screen_name":"fableson", "protected":false, "location":"Byram Township, NJ", "profile_background_color":"9ae4e8", "name":"fableson", "followers_count":52, "id":15221439, "utc_offset":-18000, "profile_text_color":"000000" }, "in_reply_to_user_id":null, "id":13052369631, "text":"Wrapping up new article on JSON for Android programmers..."} ] |
?
注意,在两个清单中除了状态更新外还有非常多附加数据。您只需要注意日期/时间,何时发布公告以及公告的内容。接下来,将向您展示解析该数据的 Android 应用程序的相关部分。整个项目见?下载?部分。
?
XMLvsJSON 应用程序
Android 应用程序很简单。其中包含 XML 和 JSON 数据资料的全部副本。用户可以任选其一进行分析。?图 2?显示 Eclipse 中项目文件的结构。(查看?图 2 的文本版本。)
图 2. Eclipse 项目的文件结构
图 3?显示选择解析选项之前的应用程序 UI:
图 3. 选择解析选项之前的应用程序 UI?
应用程序 UI 有两个按钮,Parse XML 和 Parse JSON,接着是默认文本。清单 6?包含该 UI 的布局,在项目的 res/layout 文件夹中的 main.xml 中可以找到:
清单 6. UI 的布局
<?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" > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnXML" android:text="Parse XML"></Button> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnJSON" android:text="Parse JSON file"></Button> </LinearLayout> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/ScrollView01" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="default text" android:layout_gravity="center_horizontal" android:id="@+id/txtData" /> </ScrollView> </LinearLayout> |
?
Parse XML?和?Parse JSON file?按钮是在?ScrollView
?之上定义的,ScrollView
?中含有一个?TextView
?控件。这里的意思是想要用户可以滚动结果数据。
注意多个?LinearLayout
?结构的使用。第一个是垂直对齐,其中既含有一个带有水平结构的?LinearLayout
?和一个?ScrollView
。内层LinearLayout
?含有两个?Button
?小部件。这个布局很冗长,一般在?onCreate()
?方法中调用,见?清单 7:
清单 7.?onCreate()
?方法
Button btnXML; Button btnJSON; TextView tvData; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); tvData = (TextView) findViewById(R.id.txtData); btnXML = (Button) findViewById(R.id.btnXML); btnXML.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { examineXMLFile(); } }); btnJSON = (Button) findViewById(R.id.btnJSON); btnJSON.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { examineJSONFile(); } }); } |
?
examineXMLFile()
?方法控制 XML 解析。
?
XML 解析
XML 数据解析通常是使用一个 SAX 风格的解析器完成的。对于这类解析器,您可以建立一个?InputSource
?指向源 XML 数据,并在文档 “运行” 时提供一个接收某些事件的处理程序。清单 8?展示examineXMLFile()
?方法,执行以下任务:
- 使用原始资料中的 XML 文件建立?
InputSource
- 创建一个?
SAXParser
,关联处理程序?twitterFeedHandler
(见?清单 9) - 调用解析器,在?
TextView
?小部件中显示结果,在布局文件中作为?R.id.txtData
?识别,在代码中作为?tvData
?引用 - 如果有错误,也显示在?
TextView
?中
清单 8.?examineXMLFIle()
?方法
void examineXMLFile() { try { InputSource is = new InputSource(getResources() .openRawResource(R.raw.xmltwitter)); // create the factory SAXParserFactory factory = SAXParserFactory.newInstance(); // create a parser SAXParser parser = factory.newSAXParser(); // create the reader (scanner) XMLReader xmlreader = parser.getXMLReader(); // instantiate our handler twitterFeedHandler tfh = new twitterFeedHandler(); // assign our handler xmlreader.setContentHandler(tfh); // perform the synchronous parse xmlreader.parse(is); // should be done... let's display our results tvData.setText(tfh.getResults()); } catch (Exception e) { tvData.setText(e.getMessage()); } } |
?
虽然?examineXMLFile()
?设置好了一切,但应用程序角度来看,真正的解析工作实际是在处理程序中进行的,该处理程序是在 twitterFeedHandler.java 文件中实现的。实现?DefaultHandler
?接口的类见?清单 9:
清单 9.?twitterFeedHandler
?类
public class twitterFeedHandler extends DefaultHandler { StringBuilder sb = null; String ret = ""; boolean bStore = false; int howMany = 0; twitterFeedHandler() { } String getResults() { return "XML parsed data.\nThere are [" + howMany + "] status updates\n\n" + ret; } @Override public void startDocument() throws SAXException { // initialize "list" } @Override public void endDocument() throws SAXException { } @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { try { if (localName.equals("status")) { this.sb = new StringBuilder(""); bStore = true; } if (localName.equals("user")) { bStore = false; } if (localName.equals("text")) { this.sb = new StringBuilder(""); } if (localName.equals("created_at")) { this.sb = new StringBuilder(""); } } catch (Exception ee) { Log.d("error in startElement", ee.getStackTrace().toString()); } } @Override public void endElement(String namespaceURI, String localName, String qName) throws SAXException { if (bStore) { if (localName.equals("created_at")) { ret += "Date: " + sb.toString() + "\n"; sb = new StringBuilder(""); return; } if (localName.equals("user")) { bStore = true; } if (localName.equals("text")) { ret += "Post: " + sb.toString() + "\n\n"; sb = new StringBuilder(""); return; } } if (localName.equals("status")) { howMany++; bStore = false; } } @Override public void characters(char ch[], int start, int length) { if (bStore) { String theString = new String(ch, start, length); this.sb.append(theString); } } } |
?
清单 9?中有一些值得注意的细节,首先考虑到的是 SAX 解析器是一个基于事件的解析器,这就意味着使用 SAX 进行解析时要建立真实文件。在文档开始和结束、标记开始和结束、发现数据时,事件被触发。这意味着您必须定义一个数据结构来保留感兴趣的数据、抛弃余下的。
注意,使用?StringBuilder
?和附加数据是因为一个特定数据在?InputSource
?上能通过多个读取来进行处理。千万不要以为所有数据都在给定的调用?characters()
?方法中提供。
应用程序将数据收集到一个简单的格式化字符串中。而另一个示例中则是把这些实体放在一个集合类或数据库中,特别是如果有大量的操作都发生在解析之后。
getResults()
?方法是该类特有的,用来收集这类数据的集中表示法,并将其提供给应用程序,这不是?DefaultHandler
?接口的一部分。
图 4?展示了已解析的 XML 数据。(查看?图 4 的文本版本。)
图 4. 已解析的 XML 数据
尽管从构建、管理和导航结果结构方面来说,使用 SAX 解析器解析 XML 数据并不容易,但其主要优势是快速和极大地减少了解析过程中和解析之后的 RAM 需求数量。
现在看一下 Android 解析 JSON 数据的方法。
?
JSON 解析
在用户选择 JSON 按钮时解析 JSON 数据就开始了。调用?examineJSONFile()
?方法,如?清单 10?所示。不需要额外的处理类。因为所有解析和文档管理都在 Android 提供的库中进行,所有 JSON 相关的代码都包含在这个方法中。
清单 10. 调用?examineJSONfile()
?方法
void examineJSONFile() { try { String x = ""; InputStream is = this.getResources().openRawResource(R.raw.jsontwitter); byte [] buffer = new byte[is.available()]; while (is.read(buffer) != -1); String jsontext = new String(buffer); JSONArray entries = new JSONArray(jsontext); x = "JSON parsed.\nThere are [" + entries.length() + "]\n\n"; int i; for (i=0;i<entries.length();i++) { JSONObject post = entries.getJSONObject(i); x += "------------\n"; x += "Date:" + post.getString("created_at") + "\n"; x += "Post:" + post.getString("text") + "\n\n"; } tvData.setText(x); } catch (Exception je) { tvData.setText("Error w/file: " + je.getMessage()); } } |
?
像之前显示的 XML 例程一样,代码是从原始资源文件夹的文件中读取的。数据被整体读到内存中,转换成一个?java.lang.String
,然后解析成?JSONArray
。要注意的是,正如此例所示,一个特殊的字符串能直接解析成一个数组,或者也可以直接解析成一个JSONObject
。因为 Twitter 数据是一个对象数组,整体解析成一个数组然后按顺序逐个访问对象是明智的选择。
该方法的流程简单明了,一旦数据被解析,代码建立一个类似于 XML 解析器处理程序方法的字符串表示。有趣的是数据将由您来管理;您不需要建立额外内存结构来容纳数据,同样地,应用程序预先就知道在?JSONArray
?中有多少个条目(在这个例子中是 20 个)。
尽管 JSON 解析在编程上简单得多,但并不是没有代价的。它要增加内存消耗,在处理之前整体读取数据流并进行存储。相反的,SAX XML 方法仅使用相关数据。另外,如果解析特殊 JSON 对象的内存是足够的,则这个方法将很受应用程序欢迎,特别是,几乎不需要使用 DOM 的应用程序。
?
结束语
本文在 Android 应用程序背景下介绍了 XML 和 JSON 数据交换格式。比起 JSON 方法,XML 方法更快、内存受限更小 ― 但是以增加复杂性为代价。在第二部分,我将介绍一些结合使用 JSON 方法的先进技术,例如,基于 WebKit 的 WebView 小部件,并为 Android 应用程序定制动态应用程序逻辑。
?