Android項目之旅三 簡易Mp3播放器從獲取服務器端Mp3信息

   上面我們已經把頁面弄好了,下面我們就要在裏面實現我們的功能了哦,今天主要是在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中顯示出來!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章