上面我們已經把頁面弄好了,下面我們就要在裏面實現我們的功能了哦,今天主要是在RemoteMp3Activity中做功夫,因爲項目啓動後,這個Activity要做很多事情哦:
1)從服務器上面下載mp3.xml文件,將其轉化爲string格式;
2)解析xml文件,這裏使用的是SAX解析技術,如果大家對XML和XML解析這部分不清楚的話,還是老話,自己從網上查找相關的信息去學習一下,鍛鍊自己的自學能力;將解析出來的mp3信息轉換爲MP3對象,並保存在List集合中;
3)在ListActivity中顯示出來;
好了,我們分爲上面四步,那就我們一步一步來吧!!
一、從服務器上面下載mp3.xml文件,將其轉化爲string格式,我們新建兩個類,一個類專門用來下載:HttpDownloader,一個類用來操作文件的輔助類,例如得到SD卡的路徑,創建文件,判斷文件是否存在等等,取名爲FileUtils,先來開發我們的HttpDownloader吧:
public class HttpDownloader { private URL url=null; //下載文件,該文件主要是文本類型文件,返回其中的內容 public String download(String urlStr){ StringBuffer sb=new StringBuffer(); String line=null; BufferedReader buffer=null; try { //創建一個URL對象 url=new URL(urlStr); //創建一個Http連接 HttpURLConnection urlConn=(HttpURLConnection)url.openConnection(); //使用IO流讀取數據 buffer=new BufferedReader(new InputStreamReader(urlConn.getInputStream())); while((line=buffer.readLine())!=null){ sb.append(line); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ try { buffer.close(); } catch (IOException e) { e.printStackTrace(); } } return sb.toString(); } }
這個方法的作用是從服務器上下載文本文件,並將其轉換爲String類型的字符串,在裏面一個重要的點事android提供的HttpURLConnection類,它可以通過Url地址直接獲得連接,然後進行相應的文件操作即可,通過傳入的地址參數,我這裏使用的地址是:http://192.168.1.104:8080/video/mp3.xml,將地址傳入過去,就可以從服務器上得到我們想要的xml文件中的內容信息了!
2)解析XML字符串信息,將信息轉化爲對象保存在List集合中
首先我們需要創建Mp3對象信息,取名爲Mp3Info,並生成其相應的get和set方法,重寫toString方法主要是方便項目的調試:
package com.harderxin.model; import java.io.Serializable; public class Mp3Info implements Serializable{ /** * */ private static final long serialVersionUID = 1637894703074747542L; private String id; private String mp3Name; private String mp3Size; private String lrcName; private String lrcSize; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getMp3Name() { return mp3Name; } public void setMp3Name(String mp3Name) { this.mp3Name = mp3Name; } public String getMp3Size() { return mp3Size; } public void setMp3Size(String mp3Size) { this.mp3Size = mp3Size; } public String getLrcName() { return lrcName; } public void setLrcName(String lrcName) { this.lrcName = lrcName; } public String getLrcSize() { return lrcSize; } public void setLrcSize(String lrcSize) { this.lrcSize = lrcSize; } @Override public String toString() { return "Mp3Info [id=" + id + ", mp3Name=" + mp3Name + ", mp3Size=" + mp3Size + ", lrcName=" + lrcName + ", lrcSize=" + lrcSize + "]"; } }
其次,我們需要創建XML內容解析器,因爲是SAX解析,我們這裏繼承的類是DefaultHandler(爲什麼這麼做,這就跟SAX解析相關的知識點有關係哦),然後重寫裏面的方法,代碼裏面有相應的註釋哦:
package com.harderxin.utils; import java.util.List; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.harderxin.model.Mp3Info; /** * 運用了一種適配器模式,因爲DefaultHandler實現了ContentHandler接口 * 但是ContentHandler需要實現的方法很多,所以定義一個DefaultHandler * 實現其中的方法,我們只需繼承它覆寫我們需要的方法即可 <resources> <resource> <id>1</id> <mp3.name>qmys.mp3</mp3.name> <mp3.size>3557358</mp3.size> <lrc.name>qmys.lrc</lrc.name> <lrc.size>1294</lrc.size> </resource> <resource> <id>2</id> <mp3.name>proud.mp3</mp3.name> <mp3.size>3047992</mp3.size> <lrc.name>proud.lrc</lrc.name> <lrc.size>2078</lrc.size> </resource> </resources> * @author Administrator * */ public class Mp3ListContentHandler extends DefaultHandler{ private String tagName; private Mp3Info mp3Info;//定義一個全局變量的標籤名稱 private List<Mp3Info> mp3Infos; //構造方法,將List集合傳入進去 public Mp3ListContentHandler(List<Mp3Info> mp3Infos) { super(); this.mp3Infos = mp3Infos; } //解析其中的文本<mp3.name>qmys.mp3</mp3.name>--->qmys.mp3 @Override public void characters(char[] ch, int start, int length) throws SAXException { String temp=new String(ch,start,length); if(tagName.equals("id")){ mp3Info.setId(temp); }else if(tagName.equals("mp3.name")){ mp3Info.setMp3Name(temp); }else if(tagName.equals("mp3.size")){ mp3Info.setMp3Size(temp); }else if(tagName.equals("lrc.name")){ mp3Info.setLrcName(temp); }else if(tagName.equals("lrc.size")){ mp3Info.setLrcSize(temp); } } @Override public void endDocument() throws SAXException { super.endDocument(); } //解析結束元素 @Override public void endElement(String uri, String localName, String qName) throws SAXException { if(localName.equals("resource")){ mp3Infos.add(mp3Info); } tagName=""; } //解析Document @Override public void startDocument() throws SAXException { //解析<resources>部分 super.startDocument(); } /** * 解析Element * namespaceURI 命名空間 * localName 不帶前綴部分<worker id="001">--->worker * qName 帶前綴部分<abc:worker id="001">---->abc:worker * attributes 屬性集合 <abc:worker id="001">---->id="001".... */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { //解析<resource>部分 tagName=localName; if(tagName.equals("resource")){ mp3Info=new Mp3Info(); } } }
上面解析後的xml文件將會轉換爲Mp3Info對象,最後保存在List集合中!
3)在ListActivity中顯示:
在RemoteMp3Activity中,我們根據方法傳入相應的參數即可,因爲程序中講究功能單一性,減少耦合,所以我把各部分的功能就用一個個方法在RemoteMp3Activity中寫出來:
根據地址從服務器獲取XML文件,將其轉內容換爲String類型:
/** * 從服務器上面獲取XML文件信息,並將其中信息轉換爲字符串 * @param url * @return */ private String downLoadXML(String url){ HttpDownloader httpDownloader=new HttpDownloader(); String xmlStr=httpDownloader.download(url); return xmlStr; }
根據字符串解析出Mp3信息,將其轉換爲Mp3對象保存在List集合中:
/** * 解析XML文件,並將mp3Info信息放入到List集合中 * @param xmlStr * @return */ private List<Mp3Info> parseXML(String xmlStr){ List<Mp3Info> mp3Infos=new ArrayList<Mp3Info>(); SAXParserFactory saxFactory=SAXParserFactory.newInstance(); try { XMLReader xmlReader=saxFactory.newSAXParser().getXMLReader(); xmlReader.setContentHandler(new Mp3ListContentHandler(mp3Infos)); xmlReader.parse(new InputSource(new StringReader(xmlStr))); }catch(Exception e){ e.printStackTrace(); } return mp3Infos; }
建立SimpleAdapter對象,這裏需要跟大家說明一下,因爲我們繼承了ListActivity,其中的控件顯示方式如我們以前看到的那種,就是一列一列的,它是通過我們的代碼去控制的,需要建立一個SimpleAdapter對象,裏面需要幾個參數,大家還記得我們在建立佈局文件的時候,建立過一個mp3_item.xml文件嗎,因爲這裏就需要用到它,它是其中的一個參數,另外我們還需要一個List<HashMap<String,String>>這樣一個對象,我們得通過List<Mp3Info>去轉換,其中的HashMap<String,String>裏面的鍵值要和mp3_item.xml中的id值要一樣,至於爲什麼,那就要問android系統了,因爲它裏面就是這樣規定的,我們得按照它的要求來,如果大家還是不懂的話,那就看一下android控件章節,ListActivity的案列吧,應該就明白了,我下面的代碼裏面也有註釋哦!
/** * 建立SimpleAdapter對象 * @param mp3Infos * @return */ private SimpleAdapter buildSimpleAdapter(List<Mp3Info> mp3Infos){ List<HashMap<String,String>> list=new ArrayList<HashMap<String,String>>(); HashMap<String,String> map=null; //將List<Mp3Info>轉換爲List<HashMap<String,String>>對象 //HashMap裏面的鍵值要和我們的mp3_item.xml中的id一樣 for(Mp3Info mp3Info:mp3Infos){ map=new HashMap<String,String>(); map.put("mp3_name", mp3Info.getMp3Name()); map.put("mp3_size", mp3Info.getMp3Size()); list.add(map); } //注意參數要一致,HashMap裏面的鍵值、參數中String數組、mp3_item.xml中的id要一樣 SimpleAdapter simpleAdapter=new SimpleAdapter(RemoteMp3Activity.this, list, R.layout.mp3info_item, new String[]{"mp3_name","mp3_size"}, new int[]{R.id.mp3_name,R.id.mp3_size}); return simpleAdapter; }
好了,上面三個函數都封裝好了,那就開始寫我們的顯示頁面這個方法吧,就是一步一步去調用上面的幾個方法啦!
/** * 軟件中講究功能單一性,以方便代碼的重用,減少冗餘代碼 */ private void updateListView(){ String xmlStr=downLoadXML("http://192.168.1.104:8080/mp3/mp3.xml"); mp3Infos=parseXML(xmlStr); SimpleAdapter simpleAdapter=buildSimpleAdapter(mp3Infos); setListAdapter(simpleAdapter); }
相信大家很容易弄懂,這樣寫就是方便調用,如果還有其他地方需要這些重複的代碼,我們只需要調用方法一次就可以咯,減少代碼冗餘!
好了,接下來在我們昨天寫的onCreate方法中調用顯示頁面這個方法吧!
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.remote_mp3_list); updateListView(); }
這樣寫,是不是大家覺得代碼可複用性很高呢,以後寫代碼的時候要養成這樣的好習慣哦,不要在一個方法中寫處理太多邏輯的代碼,到時候可能造成一樣的功能我們要寫很多重複的代碼,這是一個很不好的習慣,對以後程序的維護會造成很多不好的影響哦,所以大家得注意一下!!
最後還有一個事要做哦,就是我們訪問服務器的時候,需要一個權限,另外,我們訪問SD卡的時候也需要一個權限,不然android系統可不會讓你去直接操作哦,這個權限需要在AndroidMainifest.xml中進行配置,加上下面幾行代碼吧:
<!-- 獲得相應的權限 --> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
上面分別表示獲得外部訪問權限和SD卡的可讀訪問權限,一定要加上,不然會報錯!!
好了,代碼寫到這裏,我們這部分功能就算完工咯,運行一下這個項目吧,保證我們的Tomcat服務器是啓動的哦,我們就可以在模擬器上看到服務器上面的MP3文件的信息咯,我這裏顯示的是MP3文件的名稱和大小:
大家在實踐的過程中,如果有什麼問題,或者大家有什麼意見,可以給本博客留言哦,大家一起交流分享,共同學習,下一講我將會實現:點擊一個MP3文件,從服務器上找到相應的文件,下載到SD卡中,然後在LocalMp3Activity中顯示出來!!