內含Google Map元件,載入XML,Databinding顯示Markers。
原來寫普通的Android App一點也不難。網上資源十分多,自己亦寫得很開心,因為自己第一個Android App就快可以誕生了。
但寫到一步,出現很奇怪的錯誤。
就是載入XML文件時,出現NullPointerException。
這類似.NET中的NullReferenceException,簡單的說,就是找不到相應的類別物件。
在程式人員生涯中,Throw這個Exception已見慣見熟了吧?

XML結構如下 :
<?xml version="1.0" encoding="utf8"?> <table name="shopnetwork"> <row> <Code>1001</Code> <Shop>HongKong</Shop> <GeoPoint>22.3852860,113.9664120</GeoPoint> </row> <row> <Code>1002</Code> <Shop>Taiwan</Shop> <GeoPoint>22.336950,114.1578720</GeoPoint> </row> <row> <Code>1003</Code> <Shop>Japan</Shop> <GeoPoint>22.291660,114.2063270</GeoPoint> </row> </table>
經簡化後的程式碼如下 :
若轉回C#的演繹方法就是讀XML檔案至StreamReader,再轉換成XmlDocument,再讀取Node List,一個很普遍的做法。
private void initGoogleMap() {
AssetManager assetManager = this.getAssets();
InputStream inputStream = null;
String ID="", Shop = "";
try {
// Load XML for parsing.
inputStream = assetManager.open("shops.xml");
String xmlRecords = helper.readTextFile(inputStream);
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlRecords));
xmlRecords = null;
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse(is);
is = null;
doc.getDocumentElement().normalize();
NodeList listOfShops = doc.getElementsByTagName("row");
int ListOfShopsLength = listOfShops.getLength();
mIDs = new String[ListOfShopsLength];
mShops= new String[ListOfShopsLength];
// Loop the XML
for (int x = 0; x < listOfShops.getLength(); x++) {
Node ShopsNode = listOfShops.item(x);
NodeList ShopInfo = ShopsNode.getChildNodes();
for (int y = 0; y < ShopInfo.getLength(); y++) {
Node info = ShopInfo.item(y);
//Log.e("Print Node Name (Tag Name)", info.getNodeName() );
String NodeName = info.getNodeName().trim(); //<--Error!!!
String NodeValue = info.getFirstChild().getNodeValue().trim();
//Skip the use of GeoPoint.
if (NodeName.equals("ID"))
ID = NodeValue;
else if (NodeName.equals("Shop"))
Shop = NodeValue;
mIDs[x] = ID;
mShops[x]= Shop;
} //End forloop (1)
} //End forloop (2)
// End Loop XML
} catch (Exception e) {
Log.e("Catch Exception", e.getMessage());
}
}
程式去到36行就會Error。
找了原因很久,因為就這樣看,XML文件是沒有任何問題的,程式碼又找不出那裡出現問題,或者自己對Eclipse還是摸不熟,Debug方面還是不夠Visual Studio來得易。
最後唯有用最原始的方法就是Print出數據看一看,uncomment Line35後,果然有所發現。
在LogCat的Windows出現 :
為什麼在XML中,<row>與<row>之間會有"#text"的出現呢? 是因為隔行的關係? 最後在網上找到答案,"#text"的出現就是因為換行/空白或Tab字元。 這在.NET Framework的世界是不會出現的,或者是.NET的XML Class已經幫我們代勞,但肯定就是XML規格來說,XML Node是可以換行的。
有很多對此的解釋和解決方法,可以參考:
Why are there #text nodes in my xml file?
Handle Empty #text in XML DOM
How to remove #text from my Node parsing in Java dom xml parsing
我自己就用最簡單的方法,就是用 if 做一個雙重檢測。
在上面的Line 35中,加入
if (info.getNodeName().toLowerCase() != "#text" && info.hasChildNodes()) {
//...
}
完成後的程式碼就是這樣 : (見Line 37 和 49)
private void initGoogleMap() {
AssetManager assetManager = this.getAssets();
InputStream inputStream = null;
String ID="", Shop = "";
try {
// Load XML for parsing.
inputStream = assetManager.open("shops.xml");
String xmlRecords = helper.readTextFile(inputStream);
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlRecords));
xmlRecords = null;
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse(is);
is = null;
doc.getDocumentElement().normalize();
NodeList listOfShops = doc.getElementsByTagName("row");
int ListOfShopsLength = listOfShops.getLength();
mIDs = new String[ListOfShopsLength];
mShops= new String[ListOfShopsLength];
// Loop the XML
for (int x = 0; x < listOfShops.getLength(); x++) {
Node ShopsNode = listOfShops.item(x);
NodeList ShopInfo = ShopsNode.getChildNodes();
for (int y = 0; y < ShopInfo.getLength(); y++) {
Node info = ShopInfo.item(y);
//Log.e("Print Node Name (Tag Name)", info.getNodeName() );
if (info.getNodeName().toLowerCase() != "#text" && info.hasChildNodes()) {
String NodeName = info.getNodeName().trim(); //<--Error!!!
String NodeValue = info.getFirstChild().getNodeValue().trim();
//Skip the use of GeoPoint.
if (NodeName.equals("ID"))
ID = NodeValue;
else if (NodeName.equals("Shop"))
Shop = NodeValue;
mIDs[x] = ID;
mShops[x]= Shop;
}//End If
} //End forloop (1)
} //End forloop (2)
// End Loop XML
} catch (Exception e) {
Log.e("Catch Exception", e.getMessage());
}
}
沒有留言:
發佈留言