XML 在 Android 配置文件、數據交換、佈局定義中無處不在。Android 框架層大量使用 XmlPullParser** (PULL 解析)**,因其**流式、低內存、事件驅動**的特性,成為移動端解析 XML 的標準選擇。本文系統講解 XmlPullParser 核心 API、解析流程、實戰代碼模板、與 DOM/SAX 對比及最佳實踐。
<?xml version="1.0" encoding="UTF-8"?>
<colleagues>
<colleague id="1">
<name>耗子</name>
<age>24</age>
<sex>boy</sex>
</colleague>
<colleague id="2">
<name>璐璐</name>
<age>28</age>
<sex>girl</sex>
</colleague>
</colleagues>
| 方式 | 原理 | 內存佔用 | 速度 | API 複雜度 | 適用場景 |
|---|---|---|---|---|---|
| DOM | 整文檔加載為樹 | 高 (整樹在內存) | 中 | 低 (樹遍歷) | 小文件、需隨機訪問/修改 |
| SAX | 事件推送 (回調) | 極低 (流式) | 快 | 中 (需狀態機) | 大文件、單向讀取 |
| PULL (XmlPullParser) | 事件拉取 (主動 next) | 極低 (流式) | 快 | 低 (線性邏輯) | Android 首選、大文件、可控流程 |
PULL 核心優勢:**代碼控制解析節奏** (while 循環拉取事件),邏輯線性、易讀、易維護狀態,無需 SAX 的複雜 Handler 狀態機。
| 常量 | 含義 | 典型處理 |
|---|---|---|
START_DOCUMENT | 文檔開始 | 初始化列表/對象 |
END_DOCUMENT | 文檔結束 | 結束循環,返回結果 |
START_TAG | 開始標籤 ` | 獲取屬性、創建對象、標記進入字段 |
END_TAG | 結束標籤 `` | 完成對象構建、加入列表、標記退出字段 |
TEXT | 文本內容 (需單獨啟用) | 讀取字段值 |
關鍵方法:
getEventType():獲取當前事件類型。next():推進到下一事件,返回新事件類型。getName():獲取標籤名。getAttributeValue(ns, name):獲取屬性值 (命名空間通常傳 null)。nextText():**直接讀取當前 START_TAG 到對應 END_TAG 間的文本內容**,自動推進到 END_TAG,**極大簡化文本讀取**。getDepth():當前嵌套深度 (可選)。
public class Colleague {
private int id;
private String name;
private int age;
private String sex;
// Getter/Setter/toString 省略
}
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class XmlPullParserHelper {
public static List parseColleagues(String xmlFilePath) {
List colleagues = new ArrayList<>();
FileReader reader = null;
try {
reader = new FileReader(xmlFilePath);
// 1. 獲取解析器 (Android 推薦 Xml.newPullParser())
XmlPullParser parser = Xml.newPullParser();
// 或工廠模式: XmlPullParserFactory.newInstance().newPullParser();
// 2. 設置輸入源 (自動檢測編碼)
parser.setInput(reader);
// 3. 核心解析循環
int eventType = parser.getEventType();
Colleague current = null;
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
String tagName = parser.getName();
if ("colleague".equals(tagName)) {
current = new Colleague();
// 讀取屬性
current.setId(Integer.parseInt(parser.getAttributeValue(null, "id")));
} else if (current != null) {
// 讀取子標籤文本 (nextText 自動推進到 END_TAG)
switch (tagName) {
case "name": current.setName(parser.nextText()); break;
case "age": current.setAge(Integer.parseInt(parser.nextText())); break;
case "sex": current.setSex(parser.nextText()); break;
}
}
break;
case XmlPullParser.END_TAG:
if ("colleague".equals(parser.getName()) && current != null) {
colleagues.add(current);
current = null;
}
break;
}
eventType = parser.next(); // 關鍵:推進到下一事件
}
} catch (XmlPullParserException | IOException e) {
e.printStackTrace(); // 生產環境用 Logger
} finally {
if (reader != null) try { reader.close(); } catch (IOException ignored) {}
}
return colleagues;
}
}
nextText() 直接返回 "耗子" 並將游標移至 END_TAG,**省去手動處理 TEXT 事件與 END_TAG 的麻煩**。current 跟蹤當前構建對象,利用標籤名 switch 分發,邏輯清晰線性。XmlPullParserException (格式錯誤) 和 IOException (IO 錯誤)。
// 啟用命名空間感知
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
// 獲取屬性時指定命名空間 URI
String value = parser.getAttributeValue("https://schemas.android.com/apk/res/android", "id");
getDepth() 判斷層級,跳過無關分支。parser.nextTag() 直接跳至同層級下一 START_TAG/END_TAG,跳過整個子樹。
XmlSerializer serializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
serializer.setOutput(writer);
serializer.startDocument("UTF-8", true);
serializer.startTag(null, "colleagues");
serializer.startTag(null, "colleague");
serializer.attribute(null, "id", "1");
serializer.startTag(null, "name"); serializer.text("耗子"); serializer.endTag(null, "name");
serializer.endTag(null, "colleague");
serializer.endTag(null, "colleagues");
serializer.endDocument();
String xml = writer.toString();
nextText() 讀取文本內容,極大減少樣板代碼。XmlPullParserException + IOException。Simple XML、Jackson XML (註解映射)、或 Kotlinx Serialization (多格式)。掌握 XmlPullParser,不僅能應對數據解析需求,更能深入理解 Android 系統框架 (LayoutInflater、Manifest 解析、資源編譯) 的核心運作機制。**流式拉取、事件驅動、狀態機線性化** 是其設計精髓,值得每位 Android 開發者精通。