一.基礎知識
經(jīng)過這段時間的學習,我們已經(jīng)了解了Android平臺上用于解析XML的三種方式:SAX,、DOM和Pull,。并且在學習的過程中也介紹了這三種 方式各自的特點及適合的使用場合,,簡單的來說,,DOM方式最直觀和容易理解,,但是只適合XML文檔較小的時候使用,,而SAX方式更適合在Android系 統(tǒng)中使用,因為相比DOM占用內(nèi)存少,,適合處理比較大的XML文檔,最后的Pull方式使用場合和SAX類似,,但是更適合需要提前結(jié)束XML文檔解析的場 合,。
在這部分的學習中,,我們將對以上三種方式解析XML的性能進行一下簡單的比較,通過記錄比較他們讀取相同XML文檔的時間來更好的理解他們的性能,,從而使你在不同的場合更好的選擇使用那一種XML的解析方式,。
下面我們就用上面介紹的幾種方式來實現(xiàn)解析XML形式的USGS地震數(shù)據(jù)的Demo例子以作比較。
二.實例開發(fā)
我們要完成的效果圖如下圖1所示:
圖1 各種方式解析花費的時間比較
我們分別使用Java SAX,,Android SAX,,DOM和Pull方式解析相同的XML地震數(shù)據(jù),并記錄他們完成解析所花費的時間,,結(jié)果如上圖所示,。
新建一個Android工程AndroidXMLDemoCompare,。
添加進之前Demo工程AndroidXMLDemoSax中的EarthquakeEntry.java和 SaxEarthquakeHandler.java文件,工程AndroidXMLDemoSaxII中的 AndroidSaxEarthquakeHandler.java文件,,工程AndroidXMLDemoDom中的 DomEarthquakeHandler.java文件,,和工程AndroidXMLDemoPull中的 PullEarthquakeHandler.java文件,。
如果需要從本地讀取xml數(shù)據(jù)的話,同時在assets文件夾下添加保存為xml格式了的USGS地震數(shù)據(jù)USGS_Earthquake_1M2_5.xml和USGS_Earthquake_7M2_5.xml,,如果需要聯(lián)網(wǎng)讀取的話,,在manifest.xml文件中添加權(quán)限:
1 |
<uses-permission android:name="android.permission.INTERNET" />
|
并修改res\layout下的main.xml為:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas./apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:id="@+id/javaSaxBtn" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Java SAX Parse" > </Button> <Button android:id="@+id/androidSaxBtn" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Android SAX Parse" > </Button> <Button android:id="@+id/domBtn" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="DOM Parse" > </Button> <Button android:id="@+id/pullBtn" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="PULL Parse" > </Button> <TextView android:id="@+id/javaSaxText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Java SAX Parse Time:"> </TextView> <TextView android:id="@+id/androidSaxText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Android SAX Parse Time:"> </TextView> <TextView android:id="@+id/domText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="DOM Parse Time:"> </TextView> <TextView android:id="@+id/pullText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="PULL Parse Time:"> </TextView> </LinearLayout> |
主要定義了4個分別啟動Java SAX,、Android SAX,、DOM和Pull方式解析的按鈕Button,和4個顯示解析所花費時間的TextView,。
接著修改AndroidXMLDemoCompare.java文件的內(nèi)容為:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
public class AndroidXMLDemoCompare extends Activity { /** Called when the activity is first created. */ //定義變量 Button javaSaxBtn, androidSaxBtn, domBtn, pullBtn; TextView javaSaxText, androidSaxText, domText, pullText; ArrayList<EarthquakeEntry> earthquakeEntryList; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //測試各個xml解析方法的速度 javaSaxBtn = (Button)findViewById(R.id.javaSaxBtn); androidSaxBtn = (Button)findViewById(R.id.androidSaxBtn); domBtn = (Button)findViewById(R.id.domBtn); pullBtn = (Button)findViewById(R.id.pullBtn); javaSaxText = (TextView)findViewById(R.id.javaSaxText); androidSaxText = (TextView)findViewById(R.id.androidSaxText); domText = (TextView)findViewById(R.id.domText); pullText = (TextView)findViewById(R.id.pullText); javaSaxBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub javaSaxBtn.setEnabled(false); androidSaxBtn.setEnabled(false); domBtn.setEnabled(false); pullBtn.setEnabled(false); //獲取地震數(shù)據(jù)流 InputStream earthquakeStream = readEarthquakeDataFromFile(); String saxTime = "Java SAX Parse Time: 正在解析,,請稍后..."; javaSaxText.setText(saxTime); long beforeTime = System.currentTimeMillis(); //Java Sax方式進行xml解析 SAXParserFactory factory = SAXParserFactory.newInstance(); try { SAXParser parser = factory.newSAXParser(); SaxEarthquakeHandler saxHandler = new SaxEarthquakeHandler(); parser.parse(earthquakeStream, saxHandler); //獲取解析后的列表數(shù)據(jù) earthquakeEntryList = saxHandler.getEarthquakeEntryList(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } //解析完畢 long afterTime = System.currentTimeMillis(); long parseTime = (afterTime - beforeTime); saxTime = "Java SAX Parse Time: " + String.valueOf(parseTime) + "毫秒"; javaSaxText.setText(saxTime); javaSaxBtn.setEnabled(true); androidSaxBtn.setEnabled(true); domBtn.setEnabled(true); pullBtn.setEnabled(true); } }); androidSaxBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub javaSaxBtn.setEnabled(false); androidSaxBtn.setEnabled(false); domBtn.setEnabled(false); pullBtn.setEnabled(false); //獲取地震數(shù)據(jù)流 InputStream earthquakeStream = readEarthquakeDataFromFile(); String saxTime = "Android SAX Parse Time: 正在解析,,請稍后..."; androidSaxText.setText(saxTime); long beforeTime = System.currentTimeMillis(); //Android Sax方式進行解析 AndroidSaxEarthquakeHandler androidSaxHandler = new AndroidSaxEarthquakeHandler(); earthquakeEntryList = androidSaxHandler.parse(earthquakeStream); //解析完畢 long afterTime = System.currentTimeMillis(); long parseTime = (afterTime - beforeTime); saxTime = "Android SAX Parse Time: " + String.valueOf(parseTime) + "毫秒"; androidSaxText.setText(saxTime); javaSaxBtn.setEnabled(true); androidSaxBtn.setEnabled(true); domBtn.setEnabled(true); pullBtn.setEnabled(true); } }); domBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub javaSaxBtn.setEnabled(false); androidSaxBtn.setEnabled(false); domBtn.setEnabled(false); pullBtn.setEnabled(false); //獲取地震數(shù)據(jù)流 InputStream earthquakeStream = readEarthquakeDataFromFile(); String domTime = "DOM Parse Time: 正在解析,,請稍后..."; domText.setText(domTime); long beforeTime = System.currentTimeMillis(); //Dom方式進行xml解析 DomEarthquakeHandler domHandler = new DomEarthquakeHandler(); earthquakeEntryList = domHandler.parse(earthquakeStream); //解析完畢 long afterTime = System.currentTimeMillis(); long parseTime = (afterTime - beforeTime); domTime = "DOM Parse Time: " + String.valueOf(parseTime) + "毫秒"; domText.setText(domTime); javaSaxBtn.setEnabled(true); androidSaxBtn.setEnabled(true); domBtn.setEnabled(true); pullBtn.setEnabled(true); } }); pullBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub javaSaxBtn.setEnabled(false); androidSaxBtn.setEnabled(false); domBtn.setEnabled(false); pullBtn.setEnabled(false); //獲取地震數(shù)據(jù)流 InputStream earthquakeStream = readEarthquakeDataFromFile(); String pullTime = "PULL Parse Time: 正在解析,,請稍后..."; pullText.setText(pullTime); long beforeTime = System.currentTimeMillis(); //Pull方式進行xml解析 PullEarthquakeHandler pullHandler = new PullEarthquakeHandler(); earthquakeEntryList = pullHandler.parse(earthquakeStream); //解析完畢 long afterTime = System.currentTimeMillis(); long parseTime = (afterTime - beforeTime); pullTime = "PULL Parse Time: " + String.valueOf(parseTime) + "毫秒"; pullText.setText(pullTime); javaSaxBtn.setEnabled(true); androidSaxBtn.setEnabled(true); domBtn.setEnabled(true); pullBtn.setEnabled(true); } }); } private InputStream readEarthquakeDataFromFile() { //從本地獲取地震數(shù)據(jù) InputStream inStream = null; try { //1天內(nèi)2.5級以上的地震數(shù)據(jù),,約20來條地震信息 // inStream = this.getAssets().open("USGS_Earthquake_1M2_5.xml"); //7天內(nèi)2.5級以上的地震數(shù)據(jù),約200來條地震信息 inStream = this.getAssets().open("USGS_Earthquake_7M2_5.xml"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return inStream; } private InputStream readEarthquakeDataFromInternet() { //從網(wǎng)絡上獲取實時地震數(shù)據(jù) URL infoUrl = null; InputStream inStream = null; try { //1天內(nèi)2.5級以上的地震數(shù)據(jù),,約20來條地震信息 infoUrl = new URL("http://earthquake./earthquakes/catalogs/1day-M2.5.xml"); //7天內(nèi)2.5級以上的地震數(shù)據(jù),,約200來條地震信息 // infoUrl = new URL("http://earthquake./earthquakes/catalogs/7day-M2.5.xml"); URLConnection connection = infoUrl.openConnection(); HttpURLConnection httpConnection = (HttpURLConnection)connection; int responseCode = httpConnection.getResponseCode(); if(responseCode == HttpURLConnection.HTTP_OK) { inStream = httpConnection.getInputStream(); } } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return inStream; } } |
首先也是定義各個Button和TextView控件,接著為各個Button注冊單擊事件處理器,,在單擊事件處理的回調(diào)函數(shù)中,,主要就是運行對應XML解析方式的解析過程,并且分別記錄解析前和解析后的系統(tǒng)時間來計算解析所花費的時間,,
1 2 3 4 5 6 7 |
long beforeTime = System.currentTimeMillis(); //Android Sax方式進行解析 AndroidSaxEarthquakeHandler androidSaxHandler = new AndroidSaxEarthquakeHandler(); earthquakeEntryList = androidSaxHandler.parse(earthquakeStream); //解析完畢 long afterTime = System.currentTimeMillis(); long parseTime = (afterTime - beforeTime); |
完成了,,可以保存運行看下效果,。
圖2 解析時間比較
左圖是解析1天內(nèi)2.5級以上的地震數(shù)據(jù),約20來條地震信息時各個解析方式所花費的時間,,右圖是解析7天內(nèi)2.5級以上的地震數(shù)據(jù),,約180來條 地震信息時各個解析方式所花費的時間。從上圖我們可以看到Java SAX,、Android SAX和Pull方式花費的時間基本差不多,,因為他們都是基于事件處理的方式,并且Java SAX和Android SAX底層調(diào)用的都是相同的org.xml.sax包中XMLReader解析器,。而DOM方式相對來說所花費的時間就會長點,,在地震數(shù)據(jù)條數(shù)較少和較多 時都比較長。因此不管是從內(nèi)存的消耗角度或者解析使用的時間角度來考慮,,在Android平臺上的應用程序中都不太推薦使用DOM方式來解析XML數(shù)據(jù),。 但是Java SAX、Android SAX和Pull就看你喜歡使用哪個和你具體的使用場合了,,性能上他們基本相同,。
三.總結(jié)
在這部分內(nèi)容中我們學習了各個解析方式的性能比較,即解析同一個XML文檔時所花費時間的比較,,并且從結(jié)果可以看出DOM方式的性能相對來說差點,,而Java SAX、Android SAX和Pull方式的性能基本相同,。
這樣我們就比較全面的學習了Android平臺上對XML文檔進行解析的各種方式,,但目前我們只是使用現(xiàn)成的XML文檔來解析,實際上在使用過程中 我們可能還會需要構(gòu)造XML文檔,,比如可能會有需要向服務器發(fā)送XML,,或者把一份數(shù)據(jù)以XML的形式保存在本地,這塊內(nèi)容就是寫XML,,我們以后接著學 習,。