內含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()); } }
沒有留言:
發佈留言