android开发--mp3播放器项目源代码(xml文件解析,.lrc,.mp3文件下载,同时显示歌词)

来源:互联网 发布:pump it up04 编辑:程序博客网 时间:2024/05/17 04:28

一、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"><LinearLayoutandroid:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"android:padding="5dip"><TabWidgetandroid:id="@android:id/tabs"android:layout_width="fill_parent"android:layout_height="wrap_content"/><FrameLayoutandroid: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"    ><LinearLayoutandroid:id="@+id/ListLinearLayout"    android:layout_width="fill_parent"android:layout_height="wrap_content"android:scrollbars="vertical"><ListViewandroid: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"    ><LinearLayoutandroid:id="@+id/ListLinearLayout"    android:layout_width="fill_parent"android:layout_height="wrap_content"android:scrollbars="vertical"><ListViewandroid: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"?><LinearLayoutxmlns: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"/><ImageButtonandroid:id="@+id/start"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/start"/><ImageButtonandroid:id="@+id/stop"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/stop"/><ImageButtonandroid:id="@+id/over"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/over"/></LinearLayout>


 

原创粉丝点击