mp3播放器(四)(从服务器端下载mp3文件+service的应用+SDcard操作)
下载到本地的sd卡中 实现序列化接口 serializable 加一个id 表示接口 通过一个什么样的方式可以把对象变成字节码从内存中发送出去 。。。。。实体类中toString。。。能够把里面的参数都答应出来,直接写类名就行,特别方便 下载要放在线程里面执行,就创建一个内部类
下载文件的过程 1,得到用户所要下载的Mp3文件的名称,靠position获取名字 2,访问网络下载mp3文件 3,通知客户下载的结果
Mp3ListActivity.java
1 package com.example.mp3player00; 2 3 import java.io.IOException; 4 import java.io.StringReader; 5 import java.util.ArrayList; 6 import java.util.HashMap; 7 import java.util.Iterator; 8 import java.util.List; 9 10 import javax.xml.parsers.ParserConfigurationException; 11 import javax.xml.parsers.SAXParserFactory; 12 13 import org.xml.sax.InputSource; 14 import org.xml.sax.SAXException; 15 import org.xml.sax.XMLReader; 16 17 import service.DownloadService; 18 19 import xml.Mp3ListContentHandler; 20 21 import model.Mp3Info; 22 23 import com.example.download.HttpDownloader; 24 25 import android.os.Bundle; 26 import android.app.Activity; 27 import android.app.ListActivity; 28 import android.content.Intent; 29 import android.view.Menu; 30 import android.view.MenuItem; 31 import android.view.View; 32 import android.widget.ListView; 33 import android.widget.SimpleAdapter; 34 35 public class Mp3ListActivity extends ListActivity { 36 private static final int upadate=1; 37 private static final int about=2; 38 private List<Mp3Info> mp3Infos=null; 39 //以上定义常量,看到值的名字就知道按钮的名字 40 //且为后面修改提供方便 41 @Override 42 protected void onCreate(Bundle savedInstanceState) { 43 super.onCreate(savedInstanceState); 44 setContentView(R.layout.activity_mp3_list); 45 updateListView(); 46 } 47 48 @Override 49 public boolean onCreateOptionsMenu(Menu menu) { 50 // Inflate the menu; this adds items to the action bar if it is present. 51 getMenuInflater().inflate(R.menu.activity_mp3_list, menu); 52 menu.add(0, 1, 1,R.string.mp3list_update); 53 menu.add(0, 2, 2, R.string.mp3list_about); 54 return true; 55 } 56 57 @Override 58 public boolean onOptionsItemSelected(MenuItem item) { 59 // TODO Auto-generated method stub 60 //System.out.println("--->"+item.getItemId()); 61 if(item.getItemId()==upadate) 62 { 63 updateListView(); 64 65 66 } 67 else if(item.getItemId()==about) 68 { 69 //用户点击了关于按钮 70 } 71 return super.onOptionsItemSelected(item); 72 } 73 private SimpleAdapter buildSimpleAdapter(List<Mp3Info> mp3infos){ 74 //构建Adapter,首先生成一个List对象。List对象里面存的是HashMap,HashMap里面存的是String 75 76 List<HashMap<String,String>> list=new ArrayList<HashMap<String,String>>(); 77 //将Mp3Info迭代出来 78 for (Iterator iterator = mp3infos.iterator(); iterator.hasNext();) { 79 Mp3Info mp3Info = (Mp3Info) iterator.next(); 80 //生成一个HashMap对象 81 HashMap<String,String> map=new HashMap<String,String>(); 82 //构造一个map 83 map.put("mp3_name", mp3Info.getMp3Name()); 84 map.put("mp3_size", mp3Info.getMp3Size()); 85 //构造好map后添加到List中,即将HashMap添加到List中 86 list.add(map); 87 } 88 //生成adapter 89 SimpleAdapter simpleAdapter=
new SimpleAdapter(this,list,R.layout.mp3info_item,new String[]{"mp3_name","mp3_size"},new int[]{R.id.mp3_name,R.id.mp3_size}); 90 91 92 return simpleAdapter; 93 94 } 95 private void updateListView(){ 96 //用户点击了更新按钮 97 98 String xml=downloadXML("http://192.168.1.100:8080/mp3/resources.xml"); 99 //System.out.println("----->"+xml); 100 101 102 103 try { 104 mp3Infos = parse(xml); 105 } catch (IOException e) { 106 // TODO Auto-generated catch block 107 e.printStackTrace(); 108 } 109 //List<Mp3Info>可以看出一个int,String这样一个类型 110 SimpleAdapter simpleAdapter=buildSimpleAdapter(mp3Infos); 111 setListAdapter(simpleAdapter); 112 113 } 114 //写一个单独的下载函数,更加清晰 115 private String downloadXML(String urlStr) 116 { 117 118 HttpDownloader httpdownloader=new HttpDownloader(); 119 String result=httpdownloader.download(urlStr); 120 return result; 121 } 122 //在这个函数中解析xml 123 //首先生成xml解析器 124 private List<Mp3Info> parse(String xmlStr) throws IOException 125 { 126 List<Mp3Info> info=new ArrayList<Mp3Info>(); 127 SAXParserFactory saxParserFactory=SAXParserFactory.newInstance(); 128 try { 129 XMLReader xmlReader=saxParserFactory.newSAXParser().getXMLReader(); 130 Mp3ListContentHandler mp3ListContentHandler=new Mp3ListContentHandler(info); 131 xmlReader.setContentHandler(mp3ListContentHandler); 132 xmlReader.parse(new InputSource(new StringReader(xmlStr))); 133 //解析完数据都天道info里面,然后用for循环迭代出来 134 for (Iterator iterator = info.iterator(); iterator.hasNext();) { 135 Mp3Info mp3Info = (Mp3Info) iterator.next(); 136 //System.out.println(mp3Info); 137 } 138 139 140 } catch (SAXException e) { 141 // TODO Auto-generated catch block 142 e.printStackTrace(); 143 } catch (ParserConfigurationException e) { 144 // TODO Auto-generated catch block 145 e.printStackTrace(); 146 } 147 return info; 148 149 } 150 //第一个是选择的哪一个List,第二个是选择的哪一行,第三个是条目处于的位置,第四个是条目的id 151 152 //点击第一个postion是0,就是代表第一行,就是List里面第0个元素,把List看成一个有顺序的链表,链表对象就是mp3infos 153 protected void onListItemClick(ListView l, View v, int position, long id) { 154 super.onListItemClick(l, v, position, id); 155 //根据用户点击的位置来确定获得哪一个mp3info对象 156 Mp3Info mp3info=mp3Infos.get(position); 157 //System.out.println("mp3info---"+mp3info);//因为已经复写了toString方法 158 //在这里启动service 159 Intent intent=new Intent(); 160 //将mp3info放到intent里面去再传到service里面去 161 intent.putExtra("mp3info", mp3info);//将mp3info实现序列化 162 //设置跳转的目的地 163 intent.setClass(this, DownloadService.class); 164 //启动Service 165 startService(intent); 166 167 } 168 169 170 }
DownloadService.java
1 package service; 2 3 import com.example.download.HttpDownloader; 4 5 import model.Mp3Info; 6 import android.app.Service; 7 import android.content.Intent; 8 import android.os.IBinder; 9 10 public class DownloadService extends Service { 11 12 @Override 13 public IBinder onBind(Intent arg0) { 14 // TODO Auto-generated method stub 15 return null; 16 } 17 //Mp3ListActivity里面的,点击一行,onSelectedItem里的onStartService ,调用这里的onstart() 18 @Override 19 public void onStart(Intent intent, int startId) { 20 // TODO Auto-generated method stub 21 //从intent里面将mp3info取出来 22 Mp3Info mp3info=(Mp3Info) intent.getSerializableExtra("mp3info"); 23 System.out.println("service----->"+mp3info); 24 DownloadThread downloadThread=new DownloadThread(mp3info); 25 Thread thread=new Thread(downloadThread); 26 thread.start(); 27 super.onStart(intent, startId); 28 } 29 //onstar执行好,生成一个线程来执行下载 30 //创建线程的内部类 31 class DownloadThread implements Runnable{ 32 //要能接受mp3info对象,创建构造函数 33 private Mp3Info mp3Info=null; 34 public DownloadThread(Mp3Info mp3Info){ 35 this.mp3Info=mp3Info; 36 System.out.println("---in thread"+mp3Info.getMp3Name()); 37 } 38 //在run里面实现下载 39 @Override 40 public void run() { 41 System.out.println("---in thread2"+mp3Info.getMp3Name()); 42 // TODO Auto-generated method stub 43 //下载地址C:\apache-tomcat-7.0.42\webapps\mp3 44 String mp3Url="http://192.168.1.100:8080/mp3/"+mp3Info.getMp3Name(); 45 HttpDownloader httpDownloader=new HttpDownloader(); 46 int result=httpDownloader.downFile(mp3Url,"mp3/", mp3Info.getMp3Name());//放在sdcard里面哪个文件夹里 47 } 48 } 49 50 51 52 }
HttpDownloader.java
1 package com.example.download; 2 3 import java.io.BufferedReader; 4 import java.io.File; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.InputStreamReader; 8 import java.net.HttpURLConnection; 9 import java.net.MalformedURLException; 10 import java.net.URL; 11 import utils.FileUtils; 12 13 14 15 public class HttpDownloader { 16 17 /** 18 * 根据URL下载文件,前提是这个文件当中的内容是文本,函数的返回值就是文件当中的内容 19 * 1.创建一个URL对象 20 * 2.通过URL对象,创建一个HttpURLConnection对象 21 * 3.得到InputStram 22 * 4.从InputStream当中读取数据 23 * @param urlStr 24 * @return 25 */ 26 public String download(String urlStr) { 27 StringBuffer sb = new StringBuffer(); 28 String line = null; 29 BufferedReader buffer = null; 30 try { 31 // 创建一个URL对象 32 URL url = new URL(urlStr); 33 // 创建一个Http连接 34 HttpURLConnection urlConn = (HttpURLConnection) url 35 .openConnection(); 36 // 使用IO流读取数据 37 buffer = new BufferedReader(new InputStreamReader(urlConn 38 .getInputStream())); 39 while ((line = buffer.readLine()) != null) { 40 sb.append(line); 41 } 42 } catch (Exception e) { 43 e.printStackTrace(); 44 } finally { 45 try { 46 buffer.close(); 47 } catch (Exception e) { 48 e.printStackTrace(); 49 } 50 } 51 return sb.toString(); 52 } 53 public int downFile(String urlStr, String path, String fileName) { 54 InputStream inputStream = null; 55 try { 56 FileUtils fileUtils = new FileUtils(); 57 58 if (fileUtils.isFileExist( fileName,path)) { 59 return 1; 60 } else { 61 inputStream = getInputStreamFromUrl(urlStr); 62 System.out.println("urlStr----->"+urlStr+"path-->"+path+"filename-->"+fileName); 63 File resultFile = fileUtils.write2SDFromInput(path,fileName, inputStream); 64 System.out.println("httpDownloader---->"+resultFile); 65 if (resultFile == null) { 66 return -1; 67 } 68 } 69 } catch (Exception e) { 70 e.printStackTrace(); 71 return -1; 72 } finally { 73 try { 74 inputStream.close(); 75 } catch (Exception e) { 76 e.printStackTrace(); 77 } 78 } 79 return 0; 80 } 81 public InputStream getInputStreamFromUrl(String urlStr) 82 throws MalformedURLException, IOException { 83 URL url = new URL(urlStr); 84 HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); 85 InputStream inputStream = urlConn.getInputStream(); 86 return inputStream; 87 } 88 }
FileUtils.java
1 package utils; 2 3 import java.io.File; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.OutputStream; 8 9 import android.os.Environment; 10 11 public class FileUtils { 12 private String SDPATH; 13 14 public String getSDPATH() { 15 return SDPATH; 16 } 17 public FileUtils() { 18 //得到当前外部存储设备的目录 19 // /SDCARD 20 SDPATH = Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator; 21 System.out.println("判断SDCard是否存在,是否有可读权限:" 22 + Environment.MEDIA_MOUNTED.endsWith(Environment.getExternalStorageState())); 23 } 24 /** 25 * 在SD卡上创建文件 26 * 27 * @throws IOException 28 * 在哪个目录上生成这个文件,文件的名字 29 */ 30 public File creatSDFile(String fileName,String dir) throws IOException { 31 File file = new File(SDPATH+dir + fileName); 32 System.out.println("file--->"+file); 33 file.createNewFile(); 34 return file; 35 } 36 37 /** 38 * 在SD卡上创建目录 39 * 40 * @param dirName 41 */ 42 public File creatSDDir(String dir) { 43 File dirFile = new File(SDPATH + dir+File.separator); 44 System.out.println("creatSDDir?---->"+dirFile.mkdirs()); 45 return dirFile; 46 } 47 48 /** 49 * 判断SD卡上的文件夹是否存在 50 */ 51 public boolean isFileExist(String fileName,String path){ 52 File file = new File(SDPATH + path+File.separator+fileName); 53 return file.exists(); 54 } 55 56 /** 57 * 将一个InputStream里面的数据写入到SD卡中 58 */ 59 public File write2SDFromInput(String path,String fileName,InputStream input){ 60 File file = null; 61 OutputStream output = null; 62 try{ 63 creatSDDir(path); 64 file = creatSDFile( fileName,path ); 65 output = new FileOutputStream(file); 66 byte buffer [] = new byte[4 * 1024]; 67 int temp; 68 while((temp=input.read(buffer))!= -1){ 69 output.write(buffer,0,temp); 70 } 71 output.flush(); 72 } 73 catch(Exception e){ 74 e.printStackTrace(); 75 } 76 finally{ 77 try{ 78 output.close(); 79 } 80 catch(Exception e){ 81 e.printStackTrace(); 82 } 83 } 84 return file; 85 } 86 87 }
Mp3ContentHandler.java
1 package xml; 2 3 import java.util.List; 4 5 import model.Mp3Info; 6 7 import org.xml.sax.Attributes; 8 import org.xml.sax.SAXException; 9 import org.xml.sax.helpers.DefaultHandler; 10 //解析 11 //内容处理器 ContentHandler 接口是解析xm的主体 12 //handler使用的是adapter的设计模式 13 //Adapter是连接后端数据和前端显示的适配器接口, 14 //是数据和UI(View)之间一个重要的纽带。在常见的View(ListView,GridView)等地方都需要用到Adapter 15 public class Mp3ListContentHandler extends DefaultHandler { 16 private List<Mp3Info> info=null;//这边每次解析resource标签都会放入一个Mp3Info对象当中 ,一个标签就是一resource,再把每个对象放入List 17 //Mp3ListActivity在调用此类的时候会生成List并且传进来 18 private Mp3Info mp3info=null;//mp3info里面就是存放resource的值 19 private String tagname; 20 21 //添加get和set方便访问 22 public List<Mp3Info> getInfo() { 23 return info; 24 } 25 26 public void setInfo(List<Mp3Info> info) { 27 this.info = info; 28 } 29 30 //Mp3ListActivity在调用此类的时候会生成List并且传进来 31 public Mp3ListContentHandler(List<Mp3Info> info) { 32 super(); 33 this.info = info; 34 } 35 36 @Override 37 //遇到id这个标签,将值赋给Mp3Info的id属性 38 public void characters(char[] ch, int start, int length) 39 throws SAXException { 40 // TODO Auto-generated method stub 41 super.characters(ch, start, length); 42 String temp=new String(ch,start,length); 43 if(tagname.equals("id")) 44 { 45 mp3info.setId(temp);//如果标签是“id”,就把值赋予mp3info对象中的id变量中 46 } 47 else if(tagname.equals("mp3.name")) 48 { 49 mp3info.setMp3Name(temp); 50 } 51 else if(tagname.equals("mp3.size")) 52 { 53 mp3info.setMp3Size(temp); 54 } 55 else if(tagname.equals("Irc.name")) 56 { 57 mp3info.setIrcName(temp); 58 } 59 else if(tagname.equals("Irc.size")) 60 { 61 mp3info.setIrcSize(temp); 62 } 63 64 } 65 66 @Override 67 public void endDocument() throws SAXException { 68 // TODO Auto-generated method stub 69 super.endDocument(); 70 } 71 72 @Override 73 //标签解析结束 74 public void endElement(String uri, String localName, String qName) 75 throws SAXException { 76 // TODO Auto-generated method stub 77 super.endElement(uri, localName, qName); 78 if(qName.equals("resource"))//这里用qName而不是tagname 79 { 80 info.add(mp3info);//如果遇到resource结尾,那么就把这个对象放入到List中 81 } 82 tagname=""; 83 } 84 85 @Override 86 public void startDocument() throws SAXException { 87 // TODO Auto-generated method stub 88 super.startDocument(); 89 } 90 91 @Override 92 //开始解析标签 93 public void startElement(String uri, String localName, String qName, 94 Attributes attributes) throws SAXException { 95 // TODO Auto-generated method stub 96 super.startElement(uri, localName, qName, attributes); 97 this.tagname=localName; 98 if(tagname.equals("resource")) 99 { 100 mp3info=new Mp3Info(); 101 } 102 } 103 104 }
Mp3Info.java
1 package model; 2 3 import java.io.Serializable; 4 5 /** 6 * 把每一个<rescource>看成一个对象 mp3info对象 建一个实体类,代表现实中一个实体 7 * Mp3info实体类 8 * @author kyx 9 */ 10 public class Mp3Info implements Serializable{ 11 /** 12 * 实现序列化接口 13 * 可以把对象变成字节码从内存中发送出去 14 */ 15 private static final long serialVersionUID = 1L; 16 private String id; 17 private String mp3Name; 18 private String mp3Size; 19 private String IrcName; 20 private String IrcSize; 21 public String getId() { 22 return id; 23 } 24 public void setId(String id) { 25 this.id = id; 26 } 27 public String getMp3Name() { 28 return mp3Name; 29 } 30 public void setMp3Name(String mp3Name) { 31 this.mp3Name = mp3Name; 32 } 33 public String getMp3Size() { 34 return mp3Size; 35 } 36 public void setMp3Size(String mp3Size) { 37 this.mp3Size = mp3Size; 38 } 39 public String getIrcName() { 40 return IrcName; 41 } 42 public void setIrcName(String ircName) { 43 IrcName = ircName; 44 } 45 public String getIrcSize() { 46 return IrcSize; 47 } 48 public void setIrcSize(String ircSize) { 49 IrcSize = ircSize; 50 } 51 //还要生成一些构造函数,构造函数起码要有两个,一个是带参数的,一个是不带参数的 52 public Mp3Info(String id, String mp3Name, String mp3Size, String ircName, 53 String ircSize) { 54 super(); 55 this.id = id; 56 this.mp3Name = mp3Name; 57 this.mp3Size = mp3Size; 58 IrcName = ircName; 59 IrcSize = ircSize; 60 } 61 //不带参数的的构造函数 62 public Mp3Info() { 63 super(); 64 } 65 @Override 66 public String toString() { 67 return "Mp3Info [id=" + id + ", mp3Name=" + mp3Name + ", mp3Size=" 68 + mp3Size + ", IrcName=" + IrcName + ", IrcSize=" + IrcSize + "]"; 69 } 70 //toString方便测试鉴定 71 }
Manifest
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.mp3player00" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="4" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.mp3player00.Mp3ListActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name="service.DownloadService"></service> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission> </manifest>
调试中的问题
无法创建路径
问题根源
成功下载mp3文件
自信与努力 用心坚持