android開發--mp3播放器項目源代碼(xml文件解析,.lrc,.mp3文件下載,同時顯示歌詞)

一、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.java

package 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>


 

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