Android] Android XML解析学习——方式比较

分类: 嵌入式

(From:http://blog.csdn.net/ichliebephone/article/details/5981913)

一.基础知识

经过这段时间的学习,我们已经了解了Android平台上用于解析XML的三种方式:SAX、DOM和Pull。并且在学习的过程中也介绍了这三种方式各自的特点及适合的使用场合,简单的来说,DOM方式最直观和容易理解,但是只适合XML文档较小的时候使用,而SAX方式更适合在Android系统中使用,因为相比DOM占用内存少,适合处理比较大的XML文档,最后的Pull方式使用场合和SAX类似,但是更适合需要提前结束XML文档解析的场合。

在这部分的学习中,我们将对以上三种方式解析XML的性能进行一下简单的比较,通过记录比较他们读取相同XML文档的时间来更好的理解他们的性能,从而使你在不同的场合更好的选择使用那一种XML的解析方式。

下面我们就用上面介绍的几种方式来实现解析XML形式的USGS地震数据的Demo例子以作比较。

二.实例开发

我们要完成的效果图如下图1所示:

图1 各种方式解析花费的时间比较

我们分别使用Java SAX,Android SAX,DOM和Pull方式解析相同的XML地震数据,并记录他们完成解析所花费的时间,结果如上图所示。

新建一个Android工程AndroidXMLDemoCompare。

添加进之前Demo工程AndroidXMLDemoSax中的EarthquakeEntry.java和SaxEarthquakeHandler.java文件,工程AndroidXMLDemoSaxII中的AndroidSaxEarthquakeHandler.java文件,工程AndroidXMLDemoDom中的DomEarthquakeHandler.java文件,和工程AndroidXMLDemoPull中的PullEarthquakeHandler.java文件。

如果需要从本地读取xml数据的话,同时在assets文件夹下添加保存为xml格式了的USGS地震数据USGS_Earthquake_1M2_5.xml和USGS_Earthquake_7M2_5.xml,如果需要联网读取的话,在manifest.xml文件中添加权限:

  1. <uses-permission android:name="android.permission.INTERNET" />

并修改res/layout下的main.xml为:

  1. xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. >
  7. <Button
  8. android:id="@+id/javaSaxBtn"
  9. android:layout_width="fill_parent"
  10. android:layout_height="wrap_content"
  11. android:text="Java SAX Parse"
  12. >
  13. Button>
  14. <Button
  15. android:id="@+id/androidSaxBtn"
  16. android:layout_width="fill_parent"
  17. android:layout_height="wrap_content"
  18. android:text="Android SAX Parse"
  19. >
  20. Button>
  21. <Button
  22. android:id="@+id/domBtn"
  23. android:layout_width="fill_parent"
  24. android:layout_height="wrap_content"
  25. android:text="DOM Parse"
  26. >
  27. Button>
  28. <Button
  29. android:id="@+id/pullBtn"
  30. android:layout_width="fill_parent"
  31. android:layout_height="wrap_content"
  32. android:text="PULL Parse"
  33. >
  34. Button>
  35. <TextView
  36. android:id="@+id/javaSaxText"
  37. android:layout_width="fill_parent"
  38. android:layout_height="wrap_content"
  39. android:text="Java SAX Parse Time:">
  40. TextView>
  41. <TextView
  42. android:id="@+id/androidSaxText"
  43. android:layout_width="fill_parent"
  44. android:layout_height="wrap_content"
  45. android:text="Android SAX Parse Time:">
  46. TextView>
  47. <TextView
  48. android:id="@+id/domText"
  49. android:layout_width="fill_parent"
  50. android:layout_height="wrap_content"
  51. android:text="DOM Parse Time:">
  52. TextView>
  53. <TextView
  54. android:id="@+id/pullText"
  55. android:layout_width="fill_parent"
  56. android:layout_height="wrap_content"
  57. android:text="PULL Parse Time:">
  58. TextView>
  59. LinearLayout>

主要定义了4个分别启动Java SAX、Android SAX、DOM和Pull方式解析的按钮Button,和4个显示解析所花费时间的TextView。

接着修改AndroidXMLDemoCompare.java文件的内容为:

  1. public class AndroidXMLDemoCompare extends Activity {
  2. /** Called when the activity is first created. */
  3. //定义变量
  4. Button javaSaxBtn, androidSaxBtn, domBtn, pullBtn;
  5. TextView javaSaxText, androidSaxText, domText, pullText;
  6. ArrayList earthquakeEntryList;
  7. @Override
  8. public void onCreate(Bundle savedInstanceState) {
  9. super.onCreate(savedInstanceState);
  10. setContentView(R.layout.main);
  11. //测试各个xml解析方法的速度
  12. javaSaxBtn = (Button)findViewById(R.id.javaSaxBtn);
  13. androidSaxBtn = (Button)findViewById(R.id.androidSaxBtn);
  14. domBtn = (Button)findViewById(R.id.domBtn);
  15. pullBtn = (Button)findViewById(R.id.pullBtn);
  16. javaSaxText = (TextView)findViewById(R.id.javaSaxText);
  17. androidSaxText = (TextView)findViewById(R.id.androidSaxText);
  18. domText = (TextView)findViewById(R.id.domText);
  19. pullText = (TextView)findViewById(R.id.pullText);
  20. javaSaxBtn.setOnClickListener(new OnClickListener() {
  21. @Override
  22. public void onClick(View v) {
  23. // TODO Auto-generated method stub
  24. javaSaxBtn.setEnabled(false);
  25. androidSaxBtn.setEnabled(false);
  26. domBtn.setEnabled(false);
  27. pullBtn.setEnabled(false);
  28. //获取地震数据流
  29. InputStream earthquakeStream = readEarthquakeDataFromFile();
  30. String saxTime = "Java SAX Parse Time: 正在解析,请稍后...";
  31. javaSaxText.setText(saxTime);
  32. long beforeTime = System.currentTimeMillis();
  33. //Java Sax方式进行xml解析
  34. SAXParserFactory factory = SAXParserFactory.newInstance();
  35. try {
  36. SAXParser parser = factory.newSAXParser();
  37. SaxEarthquakeHandler saxHandler = new SaxEarthquakeHandler();
  38. parser.parse(earthquakeStream, saxHandler);
  39. //获取解析后的列表数据
  40. earthquakeEntryList = saxHandler.getEarthquakeEntryList();
  41. } catch (Exception e) {
  42. // TODO Auto-generated catch block
  43. e.printStackTrace();
  44. }
  45. //解析完毕
  46. long afterTime = System.currentTimeMillis();
  47. long parseTime = (afterTime - beforeTime);
  48. saxTime = "Java SAX Parse Time: " + String.valueOf(parseTime) + "毫秒";
  49. javaSaxText.setText(saxTime);
  50. javaSaxBtn.setEnabled(true);
  51. androidSaxBtn.setEnabled(true);
  52. domBtn.setEnabled(true);
  53. pullBtn.setEnabled(true);
  54. }
  55. });
  56. androidSaxBtn.setOnClickListener(new OnClickListener() {
  57. @Override
  58. public void onClick(View v) {
  59. // TODO Auto-generated method stub
  60. javaSaxBtn.setEnabled(false);
  61. androidSaxBtn.setEnabled(false);
  62. domBtn.setEnabled(false);
  63. pullBtn.setEnabled(false);
  64. //获取地震数据流
  65. InputStream earthquakeStream = readEarthquakeDataFromFile();
  66. String saxTime = "Android SAX Parse Time: 正在解析,请稍后...";
  67. androidSaxText.setText(saxTime);
  68. long beforeTime = System.currentTimeMillis();
  69. //Android Sax方式进行解析
  70. AndroidSaxEarthquakeHandler androidSaxHandler = new AndroidSaxEarthquakeHandler();
  71. earthquakeEntryList = androidSaxHandler.parse(earthquakeStream);
  72. //解析完毕
  73. long afterTime = System.currentTimeMillis();
  74. long parseTime = (afterTime - beforeTime);
  75. saxTime = "Android SAX Parse Time: " + String.valueOf(parseTime) + "毫秒";
  76. androidSaxText.setText(saxTime);
  77. javaSaxBtn.setEnabled(true);
  78. androidSaxBtn.setEnabled(true);
  79. domBtn.setEnabled(true);
  80. pullBtn.setEnabled(true);
  81. }
  82. });
  83. domBtn.setOnClickListener(new OnClickListener() {
  84. @Override
  85. public void onClick(View v) {
  86. // TODO Auto-generated method stub
  87. javaSaxBtn.setEnabled(false);
  88. androidSaxBtn.setEnabled(false);
  89. domBtn.setEnabled(false);
  90. pullBtn.setEnabled(false);
  91. //获取地震数据流
  92. InputStream earthquakeStream = readEarthquakeDataFromFile();
  93. String domTime = "DOM Parse Time: 正在解析,请稍后...";
  94. domText.setText(domTime);
  95. long beforeTime = System.currentTimeMillis();
  96. //Dom方式进行xml解析
  97. DomEarthquakeHandler domHandler = new DomEarthquakeHandler();
  98. earthquakeEntryList = domHandler.parse(earthquakeStream);
  99. //解析完毕
  100. long afterTime = System.currentTimeMillis();
  101. long parseTime = (afterTime - beforeTime);
  102. domTime = "DOM Parse Time: " + String.valueOf(parseTime) + "毫秒";
  103. domText.setText(domTime);
  104. javaSaxBtn.setEnabled(true);
  105. androidSaxBtn.setEnabled(true);
  106. domBtn.setEnabled(true);
  107. pullBtn.setEnabled(true);
  108. }
  109. });
  110. pullBtn.setOnClickListener(new OnClickListener() {
  111. @Override
  112. public void onClick(View v) {
  113. // TODO Auto-generated method stub
  114. javaSaxBtn.setEnabled(false);
  115. androidSaxBtn.setEnabled(false);
  116. domBtn.setEnabled(false);
  117. pullBtn.setEnabled(false);
  118. //获取地震数据流
  119. InputStream earthquakeStream = readEarthquakeDataFromFile();
  120. String pullTime = "PULL Parse Time: 正在解析,请稍后...";
  121. pullText.setText(pullTime);
  122. long beforeTime = System.currentTimeMillis();
  123. //Pull方式进行xml解析
  124. PullEarthquakeHandler pullHandler = new PullEarthquakeHandler();
  125. earthquakeEntryList = pullHandler.parse(earthquakeStream);
  126. //解析完毕
  127. long afterTime = System.currentTimeMillis();
  128. long parseTime = (afterTime - beforeTime);
  129. pullTime = "PULL Parse Time: " + String.valueOf(parseTime) + "毫秒";
  130. pullText.setText(pullTime);
  131. javaSaxBtn.setEnabled(true);
  132. androidSaxBtn.setEnabled(true);
  133. domBtn.setEnabled(true);
  134. pullBtn.setEnabled(true);
  135. }
  136. });
  137. }
  138. private InputStream readEarthquakeDataFromFile()
  139. {
  140. //从本地获取地震数据
  141. InputStream inStream = null;
  142. try {
  143. //1天内2.5级以上的地震数据,约20来条地震信息
  144. //          inStream = this.getAssets().open("USGS_Earthquake_1M2_5.xml");
  145. //7天内2.5级以上的地震数据,约200来条地震信息
  146. inStream = this.getAssets().open("USGS_Earthquake_7M2_5.xml");
  147. } catch (IOException e) {
  148. // TODO Auto-generated catch block
  149. e.printStackTrace();
  150. }
  151. return inStream;
  152. }
  153. private InputStream readEarthquakeDataFromInternet()
  154. {
  155. //从网络上获取实时地震数据
  156. URL infoUrl = null;
  157. InputStream inStream = null;
  158. try {
  159. //1天内2.5级以上的地震数据,约20来条地震信息
  160. infoUrl = new URL("http://earthquake.usgs.gov/earthquakes/catalogs/1day-M2.5.xml");
  161. //7天内2.5级以上的地震数据,约200来条地震信息
  162. //          infoUrl = new URL("http://earthquake.usgs.gov/earthquakes/catalogs/7day-M2.5.xml");
  163. URLConnection connection = infoUrl.openConnection();
  164. HttpURLConnection httpConnection = (HttpURLConnection)connection;
  165. int responseCode = httpConnection.getResponseCode();
  166. if(responseCode == HttpURLConnection.HTTP_OK)
  167. {
  168. inStream = httpConnection.getInputStream();
  169. }
  170. } catch (MalformedURLException e) {
  171. // TODO Auto-generated catch block
  172. e.printStackTrace();
  173. } catch (IOException e) {
  174. // TODO Auto-generated catch block
  175. e.printStackTrace();
  176. }
  177. return inStream;
  178. }
  179. }

首先也是定义各个Button和TextView控件,接着为各个Button注册单击事件处理器,在单击事件处理的回调函数中,主要就是运行对应XML解析方式的解析过程,并且分别记录解析前和解析后的系统时间来计算解析所花费的时间,

  1. long beforeTime = System.currentTimeMillis();
  2. //Android Sax方式进行解析
  3. AndroidSaxEarthquakeHandler androidSaxHandler = new AndroidSaxEarthquakeHandler();
  4. earthquakeEntryList = androidSaxHandler.parse(earthquakeStream);
  5. //解析完毕
  6. long afterTime = System.currentTimeMillis();
  7. long parseTime = (afterTime - beforeTime);

完成了,可以保存运行看下效果。

图2 解析时间比较

左图是解析1天内2.5级以上的地震数据,约20来条地震信息时各个解析方式所花费的时间,右图是解析7天内2.5级以上的地震数据,约180来条地震信息时各个解析方式所花费的时间。从上图我们可以看到Java SAX、Android SAX和Pull方式花费的时间基本差不多,因为他们都是基于事件处理的方式,并且Java SAX和Android SAX底层调用的都是相同的org.xml.sax包中XMLReader解析器。而DOM方式相对来说所花费的时间就会长点,在地震数据条数较少和较多时都比较长。因此不管是从内存的消耗角度或者解析使用的时间角度来考虑,在Android平台上的应用程序中都不太推荐使用DOM方式来解析XML数据。但是Java SAX、Android SAX和Pull就看你喜欢使用哪个和你具体的使用场合了,性能上他们基本相同。

三.总结

在这部分内容中我们学习了各个解析方式的性能比较,即解析同一个XML文档时所花费时间的比较,并且从结果可以看出DOM方式的性能相对来说差点,而Java SAX、Android SAX和Pull方式的性能基本相同。

这样我们就比较全面的学习了Android平台上对XML文档进行解析的各种方式,但目前我们只是使用现成的XML文档来解析,实际上在使用过程中我们可能还会需要构造XML文档,比如可能会有需要向服务器发送XML,或者把一份数据以XML的形式保存在本地,这块内容就是写XML,我们以后接着学习。

上一篇:WCF从零学习之设计和实现服务协定2


下一篇:前面部分(WCF全面解析1)