<?xml version="1.0" encoding="utf-8"?><feedxmlns="http://www.w3.org/2005/Atom"xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule"..."><titletype="text">newest questions tagged android - Stack Overflow</title>...
<entry> ...
</entry><entry><id>http://stackoverflow.com/q/9439999</id><re:rankscheme="http://stackoverflow.com">0</re:rank><titletype="text">Where is my data file?</title><categoryscheme="http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest/tags"term="android"/><categoryscheme="http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest/tags"term="file"/><author><name>cliff2310</name><uri>http://stackoverflow.com/users/1128925</uri></author><linkrel="alternate"href="http://stackoverflow.com/questions/9439999/where-is-my-data-file"/><published>2012-02-25T00:30:54Z</published><updated>2012-02-25T00:30:54Z</updated><summarytype="html"><p>I have an Application that requires a data file...</p></summary></entry><entry> ...
</entry>...
</feed>
publicclassStackOverflowXmlParser{// We don't use namespacesprivatestaticfinalStringns=null;publicListparse(InputStreamin)throwsXmlPullParserException,IOException{try{XmlPullParserparser=Xml.newPullParser();parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES,false);parser.setInput(in,null);parser.nextTag();returnreadFeed(parser);}finally{in.close();}}...}
Read the Feed(读取Feed)
The readFeed() 实际上并没有处理feed的内容。它只是在寻找一个 “entry” 的标签作为递归(recursively)处理整个feed的起点。如果一个标签它不是”entry”, readFeed()方法会跳过它. 当整个feed都被递归处理后,readFeed() 会返回一个包含了entry标签(包括里面的数据成员)的 List 。
123456789101112131415161718
privateListreadFeed(XmlPullParserparser)throwsXmlPullParserException,IOException{Listentries=newArrayList();parser.require(XmlPullParser.START_TAG,ns,"feed");while(parser.next()!=XmlPullParser.END_TAG){if(parser.getEventType()!=XmlPullParser.START_TAG){continue;}Stringname=parser.getName();// Starts by looking for the entry tagif(name.equals("entry")){entries.add(readEntry(parser));}else{skip(parser);}}returnentries;}
publicstaticclassEntry{publicfinalStringtitle;publicfinalStringlink;publicfinalStringsummary;privateEntry(Stringtitle,Stringsummary,Stringlink){this.title=title;this.summary=summary;this.link=link;}}// Parses the contents of an entry. If it encounters a title, summary, or link tag, hands them off// to their respective "read" methods for processing. Otherwise, skips the tag.privateEntryreadEntry(XmlPullParserparser)throwsXmlPullParserException,IOException{parser.require(XmlPullParser.START_TAG,ns,"entry");Stringtitle=null;Stringsummary=null;Stringlink=null;while(parser.next()!=XmlPullParser.END_TAG){if(parser.getEventType()!=XmlPullParser.START_TAG){continue;}Stringname=parser.getName();if(name.equals("title")){title=readTitle(parser);}elseif(name.equals("summary")){summary=readSummary(parser);}elseif(name.equals("link")){link=readLink(parser);}else{skip(parser);}}returnnewEntry(title,summary,link);}// Processes title tags in the feed.privateStringreadTitle(XmlPullParserparser)throwsIOException,XmlPullParserException{parser.require(XmlPullParser.START_TAG,ns,"title");Stringtitle=readText(parser);parser.require(XmlPullParser.END_TAG,ns,"title");returntitle;}// Processes link tags in the feed.privateStringreadLink(XmlPullParserparser)throwsIOException,XmlPullParserException{Stringlink="";parser.require(XmlPullParser.START_TAG,ns,"link");Stringtag=parser.getName();StringrelType=parser.getAttributeValue(null,"rel");if(tag.equals("link")){if(relType.equals("alternate")){link=parser.getAttributeValue(null,"href");parser.nextTag();}}parser.require(XmlPullParser.END_TAG,ns,"link");returnlink;}// Processes summary tags in the feed.privateStringreadSummary(XmlPullParserparser)throwsIOException,XmlPullParserException{parser.require(XmlPullParser.START_TAG,ns,"summary");Stringsummary=readText(parser);parser.require(XmlPullParser.END_TAG,ns,"summary");returnsummary;}// For the tags title and summary, extracts their text values.privateStringreadText(XmlPullParserparser)throwsIOException,XmlPullParserException{Stringresult="";if(parser.next()==XmlPullParser.TEXT){result=parser.getText();parser.nextTag();}returnresult;}...}
It throws an exception if the current event isn’t a START_TAG.
It consumes the START_TAG, and all events up to and including the matching END_TAG.
To make sure that it stops at the correct END_TAG and not at the first tag it encounters after the original START_TAG, it keeps track of the nesting depth.
The first time through the while loop, the next tag the parser encounters after is the START_TAG for . The value for depth is incremented to 2.
The second time through the while loop, the next tag the parser encounters is the END_TAG . The value for depth is decremented to 1.
The third time through the while loop, the next tag the parser encounters is the START_TAG . The value for depth is incremented to 2.
The fourth time through the while loop, the next tag the parser encounters is the END_TAG . The value for depth is decremented to 1.
The fifth time and final time through the while loop, the next tag the parser encounters is the END_TAG . The value for depth is decremented to 0, indicating that the element has been successfully skipped.
如果用户设置与网络连接都允许,会触发 new DownloadXmlTask().execute(url). 这会初始化一个新的 DownloadXmlTask(AsyncTask subclass) 对象并且开始执行它的 execute() 方法。
123456789101112131415161718192021222324252627
publicclassNetworkActivityextendsActivity{publicstaticfinalStringWIFI="Wi-Fi";publicstaticfinalStringANY="Any";privatestaticfinalStringURL="http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest";// Whether there is a Wi-Fi connection.privatestaticbooleanwifiConnected=false;// Whether there is a mobile connection.privatestaticbooleanmobileConnected=false;// Whether the display should be refreshed.publicstaticbooleanrefreshDisplay=true;publicstaticStringsPref=null;...// Uses AsyncTask to download the XML feed from stackoverflow.com.publicvoidloadPage(){if((sPref.equals(ANY))&&(wifiConnected||mobileConnected)){newDownloadXmlTask().execute(URL);}elseif((sPref.equals(WIFI))&&(wifiConnected)){newDownloadXmlTask().execute(URL);}else{// show error}}
下面是DownloadXmlTask是怎么工作的:
123456789101112131415161718192021
// Implementation of AsyncTask used to download XML feed from stackoverflow.com.privateclassDownloadXmlTaskextendsAsyncTask<String,Void,String>{@OverrideprotectedStringdoInBackground(String...urls){try{returnloadXmlFromNetwork(urls[0]);}catch(IOExceptione){returngetResources().getString(R.string.connection_error);}catch(XmlPullParserExceptione){returngetResources().getString(R.string.xml_error);}}@OverrideprotectedvoidonPostExecute(Stringresult){setContentView(R.layout.main);// Displays the HTML string in the UI via a WebViewWebViewmyWebView=(WebView)findViewById(R.id.webview);myWebView.loadData(result,"text/html",null);}}
// Uploads XML from stackoverflow.com, parses it, and combines it with// HTML markup. Returns HTML string.【这里可以看出应该是Download】privateStringloadXmlFromNetwork(StringurlString)throwsXmlPullParserException,IOException{InputStreamstream=null;// Instantiate the parserStackOverflowXmlParserstackOverflowXmlParser=newStackOverflowXmlParser();List<Entry>entries=null;Stringtitle=null;Stringurl=null;Stringsummary=null;CalendarrightNow=Calendar.getInstance();DateFormatformatter=newSimpleDateFormat("MMM dd h:mmaa");// Checks whether the user set the preference to include summary textSharedPreferencessharedPrefs=PreferenceManager.getDefaultSharedPreferences(this);booleanpref=sharedPrefs.getBoolean("summaryPref",false);StringBuilderhtmlString=newStringBuilder();htmlString.append("<h3>"+getResources().getString(R.string.page_title)+"</h3>");htmlString.append("<em>"+getResources().getString(R.string.updated)+" "+formatter.format(rightNow.getTime())+"</em>");try{stream=downloadUrl(urlString);entries=stackOverflowXmlParser.parse(stream);// Makes sure that the InputStream is closed after the app is// finished using it.}finally{if(stream!=null){stream.close();}}// StackOverflowXmlParser returns a List (called "entries") of Entry objects.// Each Entry object represents a single post in the XML feed.// This section processes the entries list to combine each entry with HTML markup.// Each entry is displayed in the UI as a link that optionally includes// a text summary.for(Entryentry:entries){htmlString.append("<p><a href='");htmlString.append(entry.link);htmlString.append("'>"+entry.title+"</a></p>");// If the user set the preference to include summary text,// adds it to the display.if(pref){htmlString.append(entry.summary);}}returnhtmlString.toString();}// Given a string representation of a URL, sets up a connection and gets// an input stream. 【关于Timeout具体应该设置多少,可以借鉴这里的数据,当然前提是一般情况下】// Given a string representation of a URL, sets up a connection and gets// an input stream.privateInputStreamdownloadUrl(StringurlString)throwsIOException{URLurl=newURL(urlString);HttpURLConnectionconn=(HttpURLConnection)url.openConnection();conn.setReadTimeout(10000/* milliseconds */);conn.setConnectTimeout(15000/* milliseconds */);conn.setRequestMethod("GET");conn.setDoInput(true);// Starts the queryconn.connect();returnconn.getInputStream();}