xml 是一种标记扩展语言(Extension Mark-up Language),学到这里大家对 xml 语言一定不陌生,但是它在 Android 中的运用其实只是冰山一角。抛开 Android,XML 也被广泛运用于各种数据结构中。在运用 xml 编写 Android 布局的过程中,大家有没有好奇我们写的 LinearLayout 或者 RelativeLayout 等布局是怎么变系统解析成 UI 样式的?这一节我们来揭晓谜底。
xml-的优势">1. xml 的优势
XML 是一种标记语言,我们目前接触最多的用法就是用来写布局文件。但其实,xml 被广泛用于网络数据传输中,它是一种非常流行的网络数据格式。比如我们可以使用上一节学到的 HttpURLConnect 去向 Service 发起一个 Http 请求,那么 Service 就可以将数据用 xml 的形式下发,无论是从保存还是从解析的角度,xml 都提供了极大的便利。
xml-的解析方式">2. xml 的解析方式
Android 提供了 3 种类型的解析器:DOM、SAX、XMLPullParser。在这三种类型中,唯 XMLPullParser 以其高效易用两大优点被 Android 官方推荐,在实际开发中绝大多数场景都是使用 XMLPullParser,所以本节主要介绍 XMLPullParser 的使用方法。
xmlpullparser-的组成部分">3. XMLPullParser 的组成部分
虽然写过很多 xml 布局,但是还是来系统的看一下 xml 的组成部分,一个 xml 文件通常由 4 个部分组成:
- **prolog :**通常在 xml 文件的第一行,包含一些文件的描述信息,比如版本号、编码格式等
- **Events:**以各个 Tag 开头和结尾的部分
- **Text:**介于两个 Tag 之间的内容
- **Attributes:**用来描述每个 Tag 的属性
xml-解析示例">4. XML 解析示例
xml-样本">4.1 XML 样本
下面我们来解析一个非常简单的 XML,如下:
<?xml version="1.0" encoding="utf-8"?>
<heros><hero id="1"><name>马超</name><description>刺客</description></hero><hero id="2"><name>妲己</name><description>法师</description></hero><hero id="3"><name>鲁班</name><description>射手</description></hero></heros>
xml-解析">4.2 XML 解析
以上 xml 是一个英雄列表,包含了 3 个英雄对象,每个英雄对象包含名字和描述,下面开始进行解析。
private ArrayList<Hero> parseXML(XmlPullParser parser) throws XmlPullParserException, IOException {ArrayList<Hero> heros = null;int eventType = parser.getEventType();Hero hero = null;// 判断是否结束while (eventType != XmlPullParser.END_DOCUMENT) {String name;switch (eventType) {case XmlPullParser.START_DOCUMENT:// 处理开始标签,在开始的时候创建英雄Listheros = new ArrayList();break;case XmlPullParser.START_TAG:// 处理tag开始,在这里接收英雄及英雄属性name = parser.getName();if (name.equals("hero")) {hero = new Hero();hero.id = parser.getAttributeValue(null, "id");} else if (hero != null) {if (name.equals("name")) {hero.name = parser.nextText();} else if (name.equals("description")) {hero.description = parser.nextText();}}break;case XmlPullParser.END_TAG:// 标签结束,将英雄添加到英雄列表name = parser.getName();if (name.equalsIgnoreCase("hero") && hero != null) {heros.add(hero);}}// 处理下一个标签eventType = parser.next();}return heros;}
在parseXML
方法中,首先解析 prelog,在这里创建英雄列表 List,然后一次解析英雄标签及内部属性,最后解析完一个英雄立即存入 List 中。
4.3 MainActivity 主逻辑
现在已经写好了 XML 解析方法,那么 MainActivity 的逻辑就非常简单了,我们只需写一个带有一个 Button 的布局,用于触发 XML 的解析,然后在onCreate()
中调用设置监听器,并在监听器中调用解析逻辑即可,最后将解析完的内容输入到 Logcat:
package com.emercy.myapplication;import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.parse_xml).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {XmlPullParserFactory pullParserFactory = null;try {try {pullParserFactory = XmlPullParserFactory.newInstance();} catch (XmlPullParserException e) {e.printStackTrace();}XmlPullParser parser = pullParserFactory.newPullParser();InputStream in_s = getApplicationContext().getAssets().open("heros.xml");parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);parser.setInput(in_s, null);ArrayList<Hero> heros = parseXML(parser);String text = "";for (Hero hero : heros) {text += "id : " + hero.getId() + " name : " + hero.getName() + " description : " + hero.getDescription() + "\n";}Log.d("\nXML Parser", text);} catch (XmlPullParserException | IOException e) {e.printStackTrace();}}});}
}
编译运行,点击“解析 xml”,查看 Logcat 的输出:
可以看到 log 的输出和 XML 的定义一模一样,到这里 XML 的内容就被解析到 heros 的 list 中了。
5. 小结
本节介绍了一个以前经常接触的数据格式,在 Andorid 中我们的布局可以很方便的用 XML 来编写,重新回到本节开头的问题,Android 系统是如何将我们写好的 XML 布局转换成 UI 样式的呢?是否也可以通过XmlPullParser
来完成?
当然,除了编写 Android 布局之外,XML 也是网络传输中常用的数据格式,我们可以将需要的数据通过 XML 格式存储,然后通过上一节学习的 HttpURLConnection 来进行传输。除了 XML,还有另一种数据格式非常实用,我们将在下一节揭晓。