一、mp3播放器源代碼
1、MainActivity.java:在此中主要負責播放器首頁的功能,包括服務器上的下載列表,和SD卡上已經下載的mp3文件列表package com.wyt.MP3player;
package com.wyt.MP3player;
import android.app.TabActivity;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.widget.TabHost;public class MainActivity extends TabActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);// 創建TabHost對象
TabHost tabHost = getTabHost();
// 創建得到自帶圖片對象
Resources resources = getResources();// remote頁面
// 創建Intent對象,並指向顯示遠程地址上的下載列表
Intent remoteIntent = new Intent();
remoteIntent.setClass(this, RemoteMP3ListActivity.class);
// 創建TabSpec對象,這個對象就代表了顯示remote列表的頁面
TabHost.TabSpec remoteTabSpec = tabHost.newTabSpec("Remote");
// 設置下載的文字與圖片,這裏用的是android自帶的圖片
remoteTabSpec.setIndicator("Remote",
resources.getDrawable(android.R.drawable.stat_sys_download));
// 設置該頁的內容
remoteTabSpec.setContent(remoteIntent);
// 將設置好的TabSpec對象加到TabHost當中去
tabHost.addTab(remoteTabSpec);// local頁面
// 創建Intent對象,並指向顯示遠程地址上的下載列表
Intent localIntent = new Intent();
localIntent.setClass(this, LocalMP3ListActivity.class);
// 創建TabSpec對象,這個對象就代表了顯示remote列表的頁面
TabHost.TabSpec localTabSpec = tabHost.newTabSpec("Local");
// 設置下載的文字與圖片,這裏用的是android自帶的圖片
localTabSpec.setIndicator("Local",
resources.getDrawable(android.R.drawable.stat_sys_upload_done));
// 設置該頁的內容
localTabSpec.setContent(localIntent);
// 將設置好的TabSpec對象加到TabHost當中去
tabHost.addTab(localTabSpec);
}}
2、RemoteMP3ListActivity.java:在此中主要是負責從服務器上解析xml文件,顯示服務器上的下載列表package com.wyt.MP3player;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;import com.wyt.MP3player.service.DownloaderService;
import com.wyt.download.HttpDownloader;
import com.wyt.model.MP3info;
import com.wyt.xml.Mp3ListContentHandler;public class RemoteMP3ListActivity extends ListActivity {
// 創建常量
private static final int UPDATE = 1;
private static final int ABOUT = 2;private List<MP3info> mp3info = null;
// 點擊menu後會調用該方法,在此方法中添加需要的控件
@Override
public boolean onCreateOptionsMenu(Menu menu) {// 添加按鈕(更新,關於)
menu.add(0, UPDATE, 1, R.string.mp3List_update);
menu.add(0, ABOUT, 2, R.string.mp3List_about);
return super.onCreateOptionsMenu(menu);
}@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.remote_mp3_list);
updateButton();
}// 當點擊任意一個按鈕時顯示的列表
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// 判斷得到的按鈕號,並做出相應的動作
// 點擊的是更新按鈕
if (item.getItemId() == UPDATE) {
updateButton();// 點擊的是關於按鈕
} else if (item.getItemId() == ABOUT) {}
return super.onOptionsItemSelected(item);
}private void updateButton() {
// 傳入本機的地址
String xml = downloadXML("http://10.0.2.2:8080/MP3/resources.xml");
// 調用解析xml文件類,並將解析的結果放到Mp3info對象中,最後將這些結果放到List中
mp3info = parseXml(xml);
// 生成一個List對象,並按照SimpleAdapter的標準將mp3info中的數據添加到List中去SimpleAdapter simpleAdapter = buildSimpleAdapter(mp3info);
// 將SimpleAdapter對象設置到ListActivity中去
setListAdapter(simpleAdapter);
}private SimpleAdapter buildSimpleAdapter(List<MP3info> mp3info) {
List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
// 迭代將mp3info消息循環放到list裏面去
for (Iterator iterator = mp3info.iterator(); iterator.hasNext();) {
MP3info mp3info1 = (MP3info) iterator.next();
// 創建HashMap對象,將得到的結果根據鍵值對的形式放到HashMap中區
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put("id", mp3info1.getId());
hashMap.put("mp3_name", mp3info1.getMp3Name());
hashMap.put("mp3_size", mp3info1.getMp3Size());
list.add(hashMap);
}
// 創建一個SimpleAdapter對象
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 });
return simpleAdapter;
}// 調用下載類
private String downloadXML(String urlStr) {
// 創建Download對象
HttpDownloader download = new HttpDownloader();
// 得到本機的URL地址
String result = download.download(urlStr);return result;
}// 解析xml文件
private List<MP3info> parseXml(String xmlStr) {
// 創建一個新的字符串
StringReader read = new StringReader(xmlStr);
// 創建新的輸入源SAX 解析器將使用 InputSource 對象來確定如何讀取 XML 輸入
InputSource source = new InputSource(read);
List<MP3info> info = new ArrayList<MP3info>();
try {
// 創建xml解析器
// 創建SAX工廠
SAXParserFactory sax = SAXParserFactory.newInstance();
// 創建xmlReader
XMLReader xmlReader = sax.newSAXParser().getXMLReader();Mp3ListContentHandler mp3ListContentHandler = new Mp3ListContentHandler(
info);
// 爲xmlread設置內容處理器
xmlReader.setContentHandler(mp3ListContentHandler);// 開始解析文件
xmlReader.parse(source);
// 循環輸出解析內容
for (Iterator iterator = info.iterator(); iterator.hasNext();) {
MP3info mp3info = (MP3info) iterator.next();
}
} catch (Exception e) {
e.printStackTrace();
}
return info;
}@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// 編輯用戶點擊列表中的位置,得到要下載的mp3的名字
MP3info mp3infos = mp3info.get(position);
// 生成Intent對象
Intent intent = new Intent();
// 將mp3infos放到intent中去
intent.putExtra("mp3info", mp3infos);
// 指出要跳轉的地方
intent.setClass(this, DownloaderService.class);
// 啓動Service
startService(intent);super.onListItemClick(l, v, position, id);
}}
3、HttpDownloader.java:負責下載文件package com.wyt.download;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;import com.wyt.utils.FileUtils;
public class HttpDownloader {
private URL url = null;// 根據url下載文件,前提是這個文件是文本文件,函數的返回值是文件中的內容
public String download(String urlStr) {StringBuffer sb = new StringBuffer();
String line = null;
BufferedReader br = null;try {
// 使用IO流讀取數據
br = new BufferedReader(new InputStreamReader(getUrl(urlStr)));while ((line = br.readLine()) != null) {
// 將這些字符添加到緩衝區的末端
sb.append(line);
}// 關閉流
br.close();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}return sb.toString();
}// 下載任意格式的文件
public int downFile(String urlStr, String path, String fileName) {
InputStream inputStream = null;
FileUtils fileUtils = new FileUtils();
if ((fileUtils.isFileExist(fileName, path))) {
return 1;
} else {
try {
inputStream = getUrl(urlStr);
File resultFile = fileUtils
.writeSD(path, fileName, inputStream);
if (resultFile == null) {
return -1;
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}}
return 0;
}// 封裝下載的3個步驟的方法
public InputStream getUrl(String urlStr) throws MalformedURLException,
IOException {
// 創建url
url = new URL(urlStr);
// 創建http
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
// 讀取數據
InputStream inputStream = urlConn.getInputStream();
return inputStream;
}}
4、Mp3ListContentHandler .java:負責處理xml文件
package com.wyt.xml;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;import com.wyt.model.MP3info;
public class Mp3ListContentHandler extends DefaultHandler {
private List<MP3info> info = null;
private MP3info mp3info = null;
private String tagName = null;public Mp3ListContentHandler(List<MP3info> info) {
super();
this.info = info;
}public List<MP3info> getInfo() {
return info;
}public void setInfo(List<MP3info> info) {
this.info = info;
}// 在xml文件中,若遇到某個指定標籤就將該文件內容寫入到MP3info中
@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 {}
// 在結束時,將在xml中讀到的數據放到List中
@Override
public void endElement(String uri, String localName, String name)
throws SAXException {
if (name.equals("resource")) {
info.add(mp3info);
}
// System.out.println("%%%%%%%%%%%%");
tagName = "";
}
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
super.startDocument();
}
// 在開始的時候,一遇到resource就生成MP3info對象
@Override
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
this.tagName = localName;// 遇到"resource"就生成一個MP3info對象
if (tagName.equals("resource")) {
mp3info = new MP3info();
}
}
}
5、DownloaderService .java:在一個service中進行下載文件的完成,應該Service的生命週期比Activity更穩定
package com.wyt.MP3player.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;import com.wyt.download.HttpDownloader;
import com.wyt.model.MP3info;public class DownloaderService extends Service {
@Override
public IBinder onBind(Intent intent) {return null;
}// 每次點擊ListActivity中的項目時,都會調用此方法
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 從Intent中取出mp3info
MP3info mp3info = (MP3info) intent.getSerializableExtra("mp3info");
// 每一個下載都要單獨在一個線程中進行,以免讓整個應用程序都處於等待狀態,
// 生成一個線程,並把mp3info傳入到線程中去
DownloaderThread downloaderThread = new DownloaderThread(mp3info);
// 啓動線程
Thread thread = new Thread(downloaderThread);
thread.start();
return super.onStartCommand(intent, flags, startId);
}class DownloaderThread implements Runnable {
// 創建MP3info對象
private MP3info mp3info = null;// 構造方法
public DownloaderThread(MP3info mp3info) {
this.mp3info = mp3info;
}@Override
public void run() {
// 下載地址和下載名字
String urlStr = "http://10.0.2.2:8080/MP3/" + mp3info.getMp3Name();
String urlStr2 = "http://10.0.2.2:8080/MP3/" + mp3info.getLrcName();
// 生成HttpDownloader對象
HttpDownloader httpDownloader = new HttpDownloader();
// 調用下載方法,並將下載結果存到SD卡上
int result = httpDownloader.downFile(urlStr, "mp3/",
mp3info.getMp3Name());
int result2 = httpDownloader.downFile(urlStr2, "mp3/",
mp3info.getLrcName());
// 告訴用戶下載結果
String resultMags = null;
if (result == 0 && result2 == 0) {
resultMags = "下載成功";
System.out.println(resultMags);
} else if (result == 1 && result2 == 1) {
resultMags = "文件已經存在";
System.out.println(resultMags);
} else if (result == -1 && result2 == -1) {
resultMags = "下載失敗,請重新下載!";
System.out.println(resultMags);
}
}
}
}
6、FileUtils .java:主要是負責SD卡中的數據和文件,目錄
package com.wyt.utils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;import com.wyt.model.MP3info;
import android.os.Environment;
public class FileUtils {
private String SDPATH;
private String getSDPATH(){
return SDPATH;
}
public FileUtils(){
//得到當前外部存儲設備的目錄
SDPATH=Environment.getExternalStorageDirectory()+File.separator;
}
//在SD卡上創建文件
public File createSDFile(String fileName,String dir) throws IOException{
File file=new File(SDPATH+dir+File.separator+fileName);
file.createNewFile();
return file;
}
//在SD卡上創建目錄
public File createSDDir(String dir){
File dirFile = new File(SDPATH+dir+File.separator);
return dirFile;
}
//判斷SD卡上的目錄是否存在
public boolean isFileExist(String fileName,String path){
File file = new File(SDPATH+path+File.separator+fileName);
return file.exists();
}
//將InputStream裏面的數據寫入到SD卡中去
public File writeSD(String path,String fileName,InputStream input){
File file = null;
OutputStream output = null;
try{
//調用創建SD卡目錄方法
createSDDir(path);
//調用創建SD卡文件的方法
file = createSDFile(fileName,path);
//創建文件輸出流對象
output = new FileOutputStream(file);
//4個字節的讀取
byte buffer[] = new byte[4*1024];
int temp;
//當文件的內容不爲空的時候就停止輸出
while((temp=(input.read(buffer)))!=-1){
output.write(buffer, 0, temp);
}
output.flush();
}catch(Exception e){
e.getMessage();
}finally{
try {
output.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return file;
}
//讀取目錄中的mp3文件和lrc文件的名字和大小
public List<MP3info> getMP3info(String path){
//創建MP3infoList對象
List<MP3info> mp3info = new ArrayList<MP3info>();
//得到文件的目錄
File file = new File(SDPATH+File.separator+path);
//用File的listFiles()得到每個文件,返回的是一個File數組
File[] files = file.listFiles();
//循環將文件內容放到list中去,並判斷是mp3結尾的還是一lrc結尾的
for(int i=0;i<files.length;i++){
if(files[i].getName().endsWith("mp3")){
MP3info mp3infos = new MP3info();
mp3infos.setMp3Name(files[i].getName());
mp3infos.setMp3Size(files[i].length()+"");
// mp3infos.setLrcName(files[i].getName());
// mp3infos.setLrcSize(files[i].length()+"");
mp3info.add(mp3infos);
}
}
return mp3info;
}
// public List<MP3info> getLRCinfo(String path){
// //創建MP3infoList對象
// List<MP3info> mp3info = new ArrayList<MP3info>();
// //得到文件的目錄
// File file = new File(SDPATH+File.separator+path);
// //用File的listFiles()得到每個文件,返回的是一個File數組
// File[] files = file.listFiles();
// //循環將文件內容放到list中去,並判斷是mp3結尾的還是一lrc結尾的
// for(int i=0;i<files.length;i++){
// if(files[i].getName().endsWith("lrc")){
// MP3info mp3infos = new MP3info();
// mp3infos.setLrcName(files[i].getName());
// mp3infos.setLrcSize(files[i].length()+"");
// mp3info.add(mp3infos);
// }
// }
// return mp3info;
// }
}
7、LocalMP3ListActivity .java:負責SD卡上已經下載了的MP3文件列表package com.wyt.MP3player;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;import com.wyt.model.MP3info;
import com.wyt.utils.FileUtils;import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;public class LocalMP3ListActivity extends ListActivity{
List<MP3info> mp3info = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.local_mp3_list);
}
@Override
protected void onResume() {
//創建FileUtils對象
FileUtils fileUtils = new FileUtils();
//調用FileUtils中的getMP3info(),並將結果放到mp3info中
mp3info = fileUtils.getMP3info("mp3/");
//創建HashMap對象
List<HashMap<String, String>> list = new ArrayList<HashMap<String,String>>();
//循環將文件以鍵值對的形式放到HashMap中
for (Iterator iterator = mp3info.iterator(); iterator.hasNext();) {
MP3info mp3infos = (MP3info) iterator.next();
//創建HashMap對象
HashMap<String, String> hashMap = new HashMap<String, String>();
//賦值
hashMap.put("mp3_name", mp3infos.getMp3Name());
hashMap.put("mp3_size", mp3infos.getMp3Size());
list.add(hashMap);
}
// 創建一個SimpleAdapter對象
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});
setListAdapter(simpleAdapter);
super.onResume();
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
if(mp3info != null){
//編輯用戶點擊列表中的位置,得到要下載的mp3的名字
MP3info mp3infos = mp3info.get(position);
//生成Intent對象
Intent intent = new Intent();
//將mp3infos放到intent中去
intent.putExtra("mp3info", mp3infos);
//指出要跳轉的地方
intent.setClass(this, PlayerActivity.class);
//啓動Service
startActivity(intent);
}
}
}
8、PlayerActivity .java:如果點擊一首歌,它將進入到另一個頁面,就是所謂的播放器,在播放的同時顯示歌詞,而負責播放,暫停,停止的代碼主要是PlayerService.java來負責,因爲放在Service中你就可以實現邊放歌邊看短信好或其他的事。而歌詞的顯示又需要一個類來解析歌詞,這裏用LrcProcessor.javapackage com.wyt.MP3player;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Queue;
import android.app.Activity;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.TextView;import com.wyt.MP3player.service.AppConstant;
import com.wyt.MP3player.service.PlayerService;
import com.wyt.lrc.LrcProcessor;
import com.wyt.model.MP3info;public class PlayerActivity extends Activity {
ImageButton startButton = null;
ImageButton stopButton = null;
ImageButton overButton = null;
private TextView lrcTextView = null;MediaPlayer mediaPlayer = null;
private MP3info mp3info = null;
private ArrayList<Queue> queue = null;
private Handler handler = new Handler();
private UdateTimeCallback updateTimeCallback = null;
private long begin = 0;
private long nextTimeMill = 0;
private long currentTimeMill = 0;
private String message = null;
private long pauseTimeMills = 0;
private boolean isPlaying = false;@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.player);
// 創建Intent對象
Intent intent = getIntent();
// 得到傳入Intent中的mp3info值
mp3info = (MP3info) intent.getSerializableExtra("mp3info");// 得到開始,暫停,結束按鈕
startButton = (ImageButton) findViewById(R.id.start);
stopButton = (ImageButton) findViewById(R.id.stop);
overButton = (ImageButton) findViewById(R.id.over);
lrcTextView = (TextView) findViewById(R.id.lrcTextView);// 設置監聽器
startButton.setOnClickListener(new StartButtonListener());
stopButton.setOnClickListener(new StopButtonListener());
overButton.setOnClickListener(new OverButtonListener());
}// 開始按鈕的監聽器
class StartButtonListener implements OnClickListener {
@Override
public void onClick(View v) {
// 創建一個Intent對象,用於同時Service開始播放MP3
Intent intent = new Intent();
intent.setClass(PlayerActivity.this, PlayerService.class);
intent.putExtra("mp3info", mp3info);
intent.putExtra("MSG", AppConstant.PlayerMsg.PLAY_MSG);
// 讀取LRC文件
prepareLrc(mp3info.getLrcName());
// 啓動Service
startService(intent);
// 將begin的值設置爲當前毫秒數
begin = System.currentTimeMillis();
// 執行歌詞更新
handler.postDelayed(updateTimeCallback, 5);
isPlaying = true;
}
}// 根據歌詞文件的名字來讀取歌詞文件中的信息
private void prepareLrc(String lrcName) {
try {
// 創建文件輸出流
InputStream inputStream = new FileInputStream(Environment
.getExternalStorageDirectory().getAbsolutePath()+File.separator+"mp3"+File.separator+lrcName);
// 創建歌詞處理類對象
LrcProcessor lrcProcessor = new LrcProcessor();
// 將得到的歌詞文件放到歌詞文件處理方法中,並賦給一個隊列
queue = lrcProcessor.process(inputStream);
// 創建一個UpdateTimeCallback對象,並將處理過的歌詞放到
// UdateTimeCallback()中,將歌詞顯示在對應的時間
updateTimeCallback = new UdateTimeCallback(queue);
begin = 0;
currentTimeMill = 0;
nextTimeMill = 0;
} catch (FileNotFoundException e) {
System.out.println(e.getMessage());
System.out.println("meiy");
}
}// 暫停按鈕的監聽器
class StopButtonListener implements OnClickListener {
@Override
public void onClick(View v) {
// 通知Service暫停播放MP3
Intent intent = new Intent();
intent.setClass(PlayerActivity.this, PlayerService.class);
intent.putExtra("MSG", AppConstant.PlayerMsg.PAUSE_MSG);
// 啓動Service
startService(intent);
// 如果是處於播放就移除updateTimeCallback,並且記錄當時暫停的時間
if (isPlaying) {
handler.removeCallbacks(updateTimeCallback);
pauseTimeMills = System.currentTimeMillis();
} else {
/*
* 否則就播放,重新更新歌詞,並把: 系統當前的時間-剛剛暫停時的時間=暫停了多久的時間
* ,然後將這結果+開始的時間begin=現在需要歌對應的歌詞時間, 並將正確的歌詞顯示出來
*/
handler.postDelayed(updateTimeCallback, 5);
begin = System.currentTimeMillis() - pauseTimeMills + begin;
}
isPlaying = isPlaying ? false:true;
}
}// 結束按鈕的監聽器
class OverButtonListener implements OnClickListener {
@Override
public void onClick(View v) {
// 讓Service停止播放MP3文件
Intent intent = new Intent();
intent.setClass(PlayerActivity.this, PlayerService.class);
intent.putExtra("MSG", AppConstant.PlayerMsg.STOP_MSG);
// 啓動Service
startService(intent);
// 從Handler中移除updateTimeCallback
handler.removeCallbacks(updateTimeCallback);
}
}// 更新歌詞,在一個新線程中完成
class UdateTimeCallback implements Runnable {
Queue time = null;
Queue messages = null;public UdateTimeCallback(ArrayList<Queue> queue) {
// 從ArrayList當中取出相應的隊列對象
time = queue.get(1);
messages = queue.get(1);
}@Override
public void run() {
// 計算不斷變化的時間,並以毫秒爲單位
long offset = System.currentTimeMillis() - begin;
// 如果時間爲零,也就是說還沒有時間變化,這首歌剛剛開
// 始播放的時候,就直接得到時間和與之對應的歌詞
if (currentTimeMill == 0) {
nextTimeMill = (Long) time.poll();
message = (String) messages.poll();
}
// 如果時間變化到大於下一次要更新歌詞的時間就重新設置歌詞文本
if (offset >= nextTimeMill) {
lrcTextView.setText(message);
nextTimeMill = (Long) time.poll();
message = (String) messages.poll();
}
// 每隔10毫秒就執行此類,檢查時間是否大於下次顯示歌詞的時間
currentTimeMill = currentTimeMill + 10;
handler.postDelayed(updateTimeCallback, 10);
}}
}
9、PlayerService .java
package com.wyt.MP3player.service;
import java.io.File;
import com.wyt.model.MP3info;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Environment;
import android.os.IBinder;public class PlayerService extends Service {
private boolean isPlaying = false;
private boolean isStop = false;
private boolean isReleased = false;
MediaPlayer mediaPlayer = null;@Override
public IBinder onBind(Intent intent) {
return null;
}@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 得到傳入Intent中的mp3info值
MP3info mp3info = (MP3info) intent.getSerializableExtra("mp3info");
int MSG = intent.getIntExtra("MSG", 0);
if (mp3info != null) {
if (MSG == AppConstant.PlayerMsg.PLAY_MSG) {
play(mp3info);
}
} else {
if (MSG == AppConstant.PlayerMsg.PAUSE_MSG) {
pause();
} else if (MSG == AppConstant.PlayerMsg.STOP_MSG) {
stop();
}
}
return super.onStartCommand(intent, flags, startId);
}// 播放MP3
private void play(MP3info mp3info) {
String path = getMP3Path(mp3info);
// 點擊列表,並根據路徑找到播放的文件
mediaPlayer = MediaPlayer.create(this, Uri.parse("file://" + path));
// 設置不能重複播放
mediaPlayer.setLooping(false);
// 開始播放
mediaPlayer.start();
isPlaying = true;
isReleased = false;
}// 暫停MP3
private void pause() {
if (mediaPlayer != null) {
if (!isReleased) {
// 播放時點擊暫停
if (!isStop) {
mediaPlayer.pause();
isStop = true;
isPlaying = true;
// 否則,暫停時可以播放
} else {
mediaPlayer.start();
isStop = false;
}
}
}
}// 結束播放MP3
private void stop() {
if (mediaPlayer != null) {
if (isPlaying) {
if (!isReleased) {
mediaPlayer.stop();
// 釋放播放器中不用的資源
mediaPlayer.release();
isReleased = true;
}
isPlaying = false;
}
}
}// 得到文件的目錄
private String getMP3Path(MP3info mp3info) {
String SDPATH = Environment.getExternalStorageDirectory()
.getAbsolutePath();
String path = SDPATH + File.separator + "mp3" + File.separator
+ mp3info.getMp3Name();
return path;
}
}
10、LrcProcessor .java:解析lrc文件package com.wyt.lrc;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class LrcProcessor {
public ArrayList<Queue> process(InputStream inputStream) {
// 存放時間數據
Queue<Long> timeMills = new LinkedList<Long>();
// 存放時間點所對應的歌詞
Queue<String> messages = new LinkedList<String>();
ArrayList<Queue> queue = new ArrayList<Queue>();
try {
// 創建BufferedReader對象
BufferedReader br = new BufferedReader(new InputStreamReader(
inputStream));
String temp = null;
int i = 0;// 創建正則表達式
Pattern pattern = Pattern.compile("\\[([^\\]]+)\\]");
boolean b = true;
String result = null;
// 根據正則表達式來找出時間和時間相應的歌詞
while ((temp = br.readLine()) != null) {
i++;
Matcher matcher = pattern.matcher(temp);
if (matcher.find()) {
if (result != null) {
messages.add(result);
}
String timeStr = matcher.group();
Long timeMill = time2Long(timeStr.substring(1,
timeStr.length() - 1));
if (b) {
timeMills.offer(timeMill);
}
String msg = temp.substring(10);
result = "" + msg + "\n";
} else {
result = result + temp + "\n";
}
}
messages.add(result);
queue.add(timeMills);
queue.add(messages);
} catch (Exception e) {
// TODO: handle exception
}
return queue;
}// 將時間轉化爲毫秒
public Long time2Long(String timeStr) {
String str1[] = timeStr.split(":");
int min = Integer.parseInt(str1[0]);
String str2[] = str1[1].split("\\.");
int sec = Integer.parseInt(str2[0]);
int mill = Integer.parseInt(str2[1]);
return min * 60 * 1000 + sec * 1000 + mill * 10L;
}
}
12、MP3info .java
package com.wyt.model;
import java.io.Serializable;
public class MP3info implements Serializable{
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;
}
public MP3info(String id, String mp3Name, String mp3Size, String lrcName,
String lrcSize) {
super();
this.id = id;
this.mp3Name = mp3Name;
this.mp3Size = mp3Size;
this.lrcName = lrcName;
this.lrcSize = lrcSize;
}
public MP3info() {
super();
}
@Override
public String toString() {
return "MP3info [id="+id+",mp3_name=" + mp3Name + ", mp3_size=" + mp3Size + ", lrc_name=" + lrcName + ",lrc_size="+lrcSize+"]";
}
}
13、main.xml
<TabHost xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="5dip"> <TabWidget android:id="@android:id/tabs" android:layout_width="fill_parent" android:layout_height="wrap_content"/> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="5dip"/> </LinearLayout> </TabHost>
remote_mp3_list.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <LinearLayout android:id="@+id/ListLinearLayout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:scrollbars="vertical" > <ListView android:id="@id/android:list" android:layout_width="fill_parent" android:layout_height="wrap_content" android:scrollbars="vertical" android:drawSelectorOnTop="false" android:padding="1px" /> </LinearLayout> </LinearLayout>
mp3info_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" android:paddingLeft="10dip" android:paddingRight="10dip" android:paddingTop="1dip" android:paddingBottom="1dip" > <TextView android:id="@+id/mp3_name" android:layout_height="30dip" android:layout_width="180dip" android:textSize="10pt"/> <TextView android:id="@+id/mp3_size" android:layout_height="30dip" android:layout_width="180dip" android:textSize="10pt"/> <TextView android:id="@+id/lrc_name" android:layout_height="30dip" android:layout_width="180dip" android:textSize="10pt"/> <TextView android:id="@+id/lrc_size" android:layout_height="30dip" android:layout_width="180dip" android:textSize="10pt"/> </LinearLayout>
local_mp3_list.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <LinearLayout android:id="@+id/ListLinearLayout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:scrollbars="vertical" > <ListView android:id="@id/android:list" android:layout_width="fill_parent" android:layout_height="wrap_content" android:scrollbars="vertical" android:drawSelectorOnTop="false" android:padding="1px" /> </LinearLayout> </LinearLayout>
player.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:paddingLeft="10dip" android:paddingRight="10dip" android:paddingTop="1dip" android:paddingBottom="1dip"> <TextView android:id="@+id/lrcTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="welcome to you!!" android:padding="1dip" android:layout_weight="1"/> <ImageButton android:id="@+id/start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/start"/> <ImageButton android:id="@+id/stop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/stop"/> <ImageButton android:id="@+id/over" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/over"/> </LinearLayout>