通常情况下,每个需要访问网络的应用程序都会有一个自己的服务器,我们可以向服务器提交数据,也可以从服务器上获取数据。网络上传输数据时最常用的格式有两种:XML 和 JSON。
这里以之前的一篇文章 Android网络访问之HttpURLConnection和HttpClient 为基础,继续添加代码,介绍 XML 和 JSON 的解析方式。
- 搭建 Web 服务器
这里首先需要搭建了一个简单的 Web 服务器,在这个服务器上提供一段 XML 格式文本和一段 JSON 格式文本,然后在程序里访问这个服务器,分别对其进行解析。
关于如何下载安装 Apache 服务器,这里有篇文章写得很详细: 如何从Apache官网下载windows版apache服务器
0.1 添加 XML 文件
安装好之后,在其文件夹下的 htdocs 文件夹中新建一个名为 get_data.xml 的文件,添加如下代码:
<apps> <app> <id>1</id> <name>Google Maps</name> <version>1.0</version> </app> <app> <id>2</id> <name>Chrome</name> <version>2.1</version> </app> <app> <id>3</id> <name>Google Play</name> <version>2.3</version> </app> </apps>
此时在浏览器中访问 http://127.0.0.1/get_data.xml 这个网址,显示如下:
0.2 添加 JSON 文件
在 htdocs 文件夹中新建一个名为 get_data.json 的文件,添加如下代码:
[{"id":"5", "version":"5.5", "name":"Angry Brid"}, {"id":"6", "version":"7.0", "name":"Super Mario"}, {"id":"7", "version":"9.0", "name":"Plants vs. Zombies"}]
在浏览器访问 http://127.0.0.1/get_data.json,显示如下:
注意需要开启相应服务。
- 解析 XML 格式数据
解析 XML 格式数据方法有很多种,这里介绍常用的两种:Pull 方式和 SAX 方式(此外 DOM 解析方式也比较常用)。
修改MainActivity 中 sendRequestWithHttpClient() 方法中的代码,将 http 请求网址改为 http://10.0.2.2/get_data.xml (PS: 10.0.2.2
对模拟器来说就是电脑本机 IP 地址)。
1.1 Pull
创建 parseXMLWithPull() 方法,并在 sendRequestWithHttpClient() 方法中调用它即可,且无需再发送 Message。代码如下:
/** * 解析 XML 格式数据(Pull 解析方式) */ private void parseXMLWithPull(String xmlData) { try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance();// 获取 XmlPullParserFactory实例 XmlPullParser xmlPullParser = factory.newPullParser();// 得到 XmlPullParser 的对象 xmlPullParser.setInput(new StringReader(xmlData));// 将服务器返回的数据设置进去 int eventType = xmlPullParser.getEventType();// 获取当前的解析事件 String id = ""; String name = ""; String version = ""; while (eventType != XmlPullParser.END_DOCUMENT) { String nodeName = xmlPullParser.getName(); switch (eventType) { case XmlPullParser.START_TAG:{// 开始解析某个节点 if ("id".equals(nodeName)) { id = xmlPullParser.nextText(); } else if ("name".equals(nodeName)) { name = xmlPullParser.nextText(); } else if ("version".equals(nodeName)) { version = xmlPullParser.nextText(); } break; } case XmlPullParser.END_TAG: {// 完成解析某个节点 if ("app".equals(nodeName)) { Log.e("MainActivity", "id is " + id); Log.e("MainActivity", "name is " + name); Log.e("MainActivity", "version is " + version); } break; } default: break; } eventType = xmlPullParser.next(); } } catch (XmlPullParserException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } }
运行程序,LogCat 中显示如下:
说明已经将 XML 文件中的内容成功解析出来了。
1.2 SAX
SAX 解析较 Pull 方式略复杂(通常会新建一个类继承自 DefaultHandler,并重写父类的5个方法),但在语义方面更清晰。
新建一个类 ContentHandler 继承自 DefaultHandler,代码如下:
/** * 解析 XML 格式数据(SAX 解析方式) */ public class ContentHandler extends DefaultHandler { private String nodeName; private StringBuilder id; private StringBuilder name; private StringBuilder version; @Override public void startDocument() throws SAXException {// 开始解析XML时调用 id = new StringBuilder(); name = new StringBuilder(); version = new StringBuilder(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // 开始解析某个结点时调用 // 记录当前结点名 nodeName = localName; } @Override public void characters(char[] ch, int start, int length) throws SAXException { // 获取结点内容时调用。 // 在获取结点内容时,本方法可能被调用多次,一些换行符也被当做内容解析出来,需要做好控制(如本例中的trim方法) // 根据当前的结点名判断将内容添加到哪一个StringBuilder中 if ("id".equals(nodeName)) { id.append(ch, start, length); } else if ("name".equals(nodeName)) { name.append(ch, start, length); } else if ("version".equals(nodeName)) { version.append(ch, start, length); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // 结束解析某个结点时调用 if ("app".equals(localName)) { Log.e("ContentHandler", "id is " + id.toString().trim()); Log.e("ContentHandler", "name is " + name.toString().trim()); Log.e("ContentHandler", "version is " + version.toString().trim()); // 清空StringBuilder id.setLength(0); name.setLength(0); version.setLength(0); } } @Override public void endDocument() throws SAXException { // 完成解析XML时调用 } }
接下来在 MainActivity 中添加 parseXMLWithSAX() 方法,并在 sendRequestWithHttpClient() 方法中调用它即可,代码如下:
/** * 解析 XML 格式数据(SAX 解析方式) */ private void parseXMLWithSAX(String xmlData) { SAXParserFactory factory = SAXParserFactory.newInstance(); try { XMLReader xmlReader = factory.newSAXParser().getXMLReader(); ContentHandler handler = new ContentHandler(); xmlReader.setContentHandler(handler);// 将ContentHandler的实例设置到XMLReader中 xmlReader.parse(new InputSource(new StringReader(xmlData)));// 开始执行解析 } catch (Exception e) { e.printStackTrace(); } }
运行程序,效果同上。
- 解析 JSON 格式数据
JSON 与 XML 相比的优缺点:
优点:体积小,省流量。
缺点:语义性较差。
解析 JSON 格式的数据也有多种方法,这里介绍两种:JSONObject 和 GSON。
2.1 JSONObject
在 MainActivity 中创建 parseJSONWithJSONObject() 方法,并在 sendRequestWithHttpClient() 方法中调用它即可,同样无需发送 Message。代码如下:
/** * 解析 JSON 格式的数据(JSONObject 解析方式) */ private void parseJSONWithJSONObject(String jsonData) { try { JSONArray jsonArray = new JSONArray(jsonData);// 将服务器返回的数据传入 JSONArray 对象中 for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); String id = jsonObject.getString("id"); String name = jsonObject.getString("name"); String version = jsonObject.getString("version"); Log.e("MainActivity", "id is " + id); Log.e("MainActivity", "name is " + name); Log.e("MainActivity", "version is " + version); } } catch (JSONException e) { e.printStackTrace(); } }
注意要将 http 请求网址改为 http://10.0.2.2/get_data.json
可以看到这种方式代码更简单。运行程序,LogCat 中显示如下:
2.2 GSON
GSON 并未添加到 Android 的官方 API 中,因此若想使用的话需要在项目中添加 GSON 的 jar 包(下载 后将其添加到 libs 文件夹下即可)。
新建一个 APP 类,代码如下:
public class App { private String id; private String name; private String version; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } }
在 MainActivity 中创建 parseJSONWithGSON() 方法,并在 sendRequestWithHttpClient() 方法中调用它即可,同样无需发送 Message。代码如下:
/** * 解析 JSON 格式的数据(GSON 解析方式) */ private void parseJSONWithGSON(String jsonData) { Gson gson = new Gson(); // 借助TypeToken将期望解析成的数据类型传入到fromJson()方法中 List<App> appList = gson.fromJson(jsonData, new TypeToken<List<App>>() {}.getType()); for (App app : appList) { Log.e("MainActivity", "id is " + app.getId()); Log.e("MainActivity", "name is " + app.getName()); Log.e("MainActivity", "version is " + app.getVersion()); } }
运行程序,结果同上。
源码下载
《第一行代码》 学习笔记。
<p>版权声明:本文为博主原创文章,未经博主允许不得转载。</p>