使用 XmlPullParser 在 Android 上來解析 XML 文件是高效能且易維護的。由於歷史原因,XML 文件解析在 Android 系統上有兩種實現:
- KXmlParser: 通過 XmlPullParserFactory.newPullParser() 函數獲取
- ExpatPullParser: 通過 Xml.newPullParser() 函數獲取
public void parseXml(Reader reader) throws XmlPullParserException, IOException {
XmlPullParser parser = Xml.newPullParser(); parser.setInput(reader);
parser.nextTag(); parser.require(XmlPullParser.START_TAG, null, "menu");
while (parser.nextTag() == XmlPullParser.START_TAG)
{
parser.require(XmlPullParser.START_TAG, null, "item"); String itemText = parser.nextText(); parser.nextTag(); // this call shouldn’t be necessary!
parser.require(XmlPullParser.END_TAG, null, "item");
System.out.println("menu option: " + itemText);
}
parser.require(XmlPullParser.END_TAG, null, "menu");
}
在 Android 4.0 版本中,Android 的團隊修改了 Xml.newPullParser() 函數的實現,返回 KxmlParser 並且刪除了 ExpatPullParser 類,這樣修復了nextTag() bug。不幸的是那些按照上面的代碼修改該錯誤的程序在 4.0 系統上運行將會崩潰。
org.xmlpull.v1.XmlPullParserException: expected: END_TAG {null}item (position:START_TAG <item>@1:37 in java.io.StringReader@40442fa8)
at org.kxml2.io.KXmlParser.require(KXmlParser.java:2046)
at com.publicobject.waffles.Menu.parseXml(Menu.java:25)
at com.publicobject.waffles.Menu.main(Menu.java:32)
可以按照如下的方式來修復該問題,調用函數 nextText() 後只有當前位置不是 END_TAG 的時候才調用 nextTag()。
while (parser.nextTag() == XmlPullParser.START_TAG) {
parser.require(XmlPullParser.START_TAG, null, "item");
String itemText = parser.nextText();
if (parser.getEventType() != XmlPullParser.END_TAG) {
parser.nextTag();
}
parser.require(XmlPullParser.END_TAG, null, "item");
System.out.println("menu option: " + itemText);
}
上面的代碼在所有的 Android 版本上都能正常運行。如果您的程序使用了 nextText() 函數,請使用下面的幫助函數來替代所有的 nextText() 函數調用:
private String safeNextText(XmlPullParser parser)
throws XmlPullParserException, IOException {
String result = parser.nextText();
if (parser.getEventType() != XmlPullParser.END_TAG) {
parser.nextTag();
}
return result;
}
現在只使用一個 XmlPullParser 實現,可以讓維護系統更簡單,並且可以讓 Android 開發團隊集中精力在提高系統性能上面。
沒有留言:
張貼留言