android音乐播放器之歌词下载、处理、开始、同步

**

程序源代码在底部

**

先来看看效果

下载

/*** 自定义下载方法,调用系统DownloadManager下载* * @param myUrl*            下载所需要的链接* @param path*            本地SDcard中的文件夹* @param fileName*            保存到文件名* @return void* */public void download(final String myUrl, final String path,final String fileName) {try {Runnable networkTask = new Runnable() {@Overridepublic void run() {         // 创建下载任务DownloadManager.Request request = new DownloadManager.Request(Uri.parse(myUrl));// 设置为通知栏和下载界面皆不显示,需要添加权限DOWNLOAD_WITHOUT_NOTIFICATIONrequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);request.setVisibleInDownloadsUi(false);// sdcard的目录下的mymusicplayer文件夹request.setDestinationInExternalPublicDir(path, fileName);// 将下载请求加入下载队列DownloadManager downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);// 加入下载队列后会给该任务返回一个long型的id,long id = downloadManager.enqueue(request);// 根据不同类型赋值idif (isDownloadLrc) {Log.i("下载歌词开始", String.valueOf(id));Log.i("歌词地址", myUrl);isDownloadLrc = false;lrcReference = id;} }};// 开启一个子线程,进行网络操作new Thread(networkTask).start();} catch (Exception e) {e.printStackTrace();        }}

下载完成后处理:

    /*** 初始化下载等待,下载任务完进行处理* * @return void* */private void initDownload() {IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);receiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {long reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);downloadSuccess(reference);}};registerReceiver(receiver, filter);}/*** 下载完成处理* * @param reference*            下载序号id* */public void downloadSuccess(long reference) {try {if (reference == lrcReference) { // 处理歌词Log.i("歌词下载完", String.valueOf(reference));File file = new File(LrcPath);if (!file.exists()) { // 本地文件不存在return;}initLrc(LrcPath);int temp = mMediaPlayer01.getCurrentPosition();currentIndex = findIndexOfTime(temp);lrcExits = true;} } catch (RuntimeException e) {}}

我调用了系统的DownloadManager下载,之前是自己写的,但有时候会出错,感觉系统这个下载也挺好用的,这函数用来下载其他文件也可以。定义一个广播接收器接收,下载完后,就进行处理.

接下来是处理,读取Lrc文件,这是一个类,在别人的基础上修改的,文末给上链接,希望大神莫怪

package com.example.musicplayer;import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;import android.util.Log;/*** 歌词处理* */
public class LrcRead {private List<Map<String, Object>> word_Time_List = new ArrayList<Map<String, Object>>();/*** 处理歌词文件* * @param path*            歌词路径* @return void  throws IndexOutOfBoundsException* */public void readLRC(String path) throws IndexOutOfBoundsException{File file = new File(path);try {FileInputStream fileInputStream = new FileInputStream(file);//这里的编码,我用utf-8,全部乱码,用gb2312和gbk中英文不会乱码,不知道咋滴InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "gbk");BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String s = "";//读取歌词while ((s = bufferedReader.readLine()) != null) {                int time = addTimeToList(s); //添加歌词时间间                  if(s.length()==0 || time == -1)continue;if ((s.indexOf("[ar:") != -1) || (s.indexOf("[ti:") != -1)|| (s.indexOf("[by:") != -1)) {s = s.substring(s.indexOf(":") + 1, s.indexOf("]"));                    } else {    String ss = s.substring(s.indexOf("["), s.indexOf("]") + 1);                    s = s.replace(ss, "");                  }Map<String, Object> map4 = new HashMap<String, Object>();map4.put("time", time);map4.put("word", s);word_Time_List.add(map4);}bufferedReader.close();inputStreamReader.close();fileInputStream.close();} catch (FileNotFoundException e) {e.printStackTrace();            } catch (IOException e) {e.printStackTrace();} catch (IndexOutOfBoundsException e) {e.printStackTrace();}}/*** 获取歌词+时间列表* * @return 所有歌词* */public List<Map<String, Object>> getWordTimeList() {return word_Time_List;}/*** 分离出时间* * @param string*            时间* @return 毫秒* */private int timeHandler(String string) {string = string.replace(".", ":");String timeData[] = string.split(":");// 分离出分、秒并转换为整型int minute = Integer.parseInt(timeData[0]);int second = Integer.parseInt(timeData[1]);int millisecond = Integer.parseInt(timeData[2]);// 计算上一行与下一行的时间转换为毫秒数int currentTime = (minute * 60 + second) * 1000 + millisecond * 10;return currentTime;}/*** 添加时间到列表*/private int addTimeToList(String string) {int t = -1;Matcher matcher = Pattern.compile("\\[\\d{1,2}:\\d{1,2}([\\.:]\\d{1,2})?\\]").matcher(string);if (matcher.find()) {String str = matcher.group();   t = timeHandler(str.substring(1, str.length() - 1));}return t;}/*** 清空列表*/public void reset(){word_Time_List.clear();}
}

读取歌词时,原文是把歌词和时间文件分开成两个列表的,这样做,在歌词同步的时候挺麻烦的,特别是有些歌词,前面几行是作者、歌名、广告等,又没标注时间,导致两个列表长度也不一致,同步时添加了难度,所以我把他们合并在一起了。

调用方法:

    /*** 初始化歌词,调用LrcRead类* * @param LrcPath*            歌词路径* * @return void*/public void initLrc(String LrcPath) {try {lrcHandler.reset(); // 先清空原有的数据lrcHandler.readLRC(LrcPath);word_Time_List = lrcHandler.getWordTimeList();tvCurrentWord.setText("歌词准备完毕");} catch (IllegalArgumentException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (IllegalStateException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}

歌词的同步

/*** 开始或继续SeekBar* * @return void* */private void startSeekBar() {seekBar.setEnabled(true);try {mRunnable = new Runnable() {public void run() {// 每3秒执行一次,执行进度条mHandler.postDelayed(mRunnable, 100); // 给自己发送消息,自运行int temp = mMediaPlayer01.getCurrentPosition();seekBar.setProgress(temp);String time = formatTime(temp); // 格式化时间tvCurrentTime.setText(time);//歌词同步if (lrcExits) { // 歌词存在// 防止下标越界if (currentIndex != word_Time_List.size()) {int lrcTime = Integer.parseInt(word_Time_List.get(currentIndex).get("time").toString());// 如果当前播放时间和歌词时间在一定范围,这里设置0到200毫秒,切换歌词if (lrcTime >= temp && lrcTime <= temp + 200) {String Currentword = word_Time_List.get(currentIndex).get("word").toString();String nextWord = null;if (currentIndex + 1 != word_Time_List.size() - 1)nextWord = word_Time_List.get(currentIndex + 1).get("word").toString();elselrcExits = false;tvCurrentWord.setText(Currentword);tvNextWord.setText(nextWord);//写到textview上currentIndex++;if (currentIndex > word_Time_List.size() - 1)lrcExits = false;}}}}};// 通过Handler启动线程mHandler.post(mRunnable); // 发送消息,启动线程运行} catch (Exception e) {}}

歌词的同步,获取刚刚解析到的歌词列表中的时间,与当前播放的时间比较,相差200ms,就把当前歌词和下一句替换上去两个textview。歌词同步还有一个方法比较重要的:

/*** 在mTimeList中查找歌词序号* * @param targetTime*            当前播放的时间* @return index 当前时间附近的歌词序号*/public int findIndexOfTime(int targetTime) {int index = 0;int currentTime;if (word_Time_List.size() <= 1)return 1;for (int i = 0; i < word_Time_List.size() - 1; i++) {currentTime = Integer.parseInt(word_Time_List.get(i).get("time").toString());if (targetTime <= currentTime) {  //列表时间大于当前时间index = i;break;}}return index;}

该方法时遍历歌词列表的时间,如果列表时间大于当前播放时间,就把这个序号返回去,在拉动播放进度条时调用这个同步歌词,歌词需要下载时也调用,毕竟下载和处理歌词也是需要时间的,有一些歌曲一开始就播放了,所以需要跳过已经播放的歌词。

调用方法:

int temp = mMediaPlayer01.getCurrentPosition();
String time = formatTime(temp);  //把获取到的时间转换一下,转换成毫秒的字符串currentIndex = findIndexOfTime(temp);  //currentIndex 为当前歌词列表的序号,int,全局变量

(函数非原创,忘了从哪里拿来改的了)
formatTime():

/*** 时间转换* * @param ms*            需要转化的时间,单位毫秒* @return String 返回00:00格式的分秒时间*/public static String formatTime(int ms) {int ss = 1000; // 秒int mi = ss * 60; // 分int minute = ms / mi;// 计算分int second = (ms - minute * mi) / ss; // 计算秒StringBuffer sb = new StringBuffer();if (minute > 0) {sb.append(minute + ":");} else {sb.append("00:");}if (second > 0 && second <= 9) {sb.append("0" + second);} else if (second > 9) {sb.append(second);} else {sb.append("00");}return sb.toString();}

程序源代码-MusicPlayer

歌词处理类来源:http://www.cnblogs.com/wenjiang/archive/2013/05/06/3063259.html

android音乐播放器之歌词下载、处理、开始、同步相关推荐

  1. android音乐播放器之----天天动听

    下载手机软件的时候,随意的下了个天天动听,觉得喜欢,就仿照着他的UI做了个简单的音乐播放器,还不完善,只是在工作之余随便做做,贴图: 本文来自CSDN丹丹博库,转载请必须注明出处: http://bl ...

  2. android 音乐播放器-------歌词同步 lrc

    lrc格式 : [al:这首歌所在的唱片集 ] [ar:歌词作者 ] [by:本LRC文件的创建者 ] [offset:+/- 以毫秒为单位整体时间戳调整,+增加,-减小 ] [re:创建此LRC文件 ...

  3. android 本地lrc 歌词同步,android 音乐播放器-------歌词同步 lrc

    lrc格式 : [al:这首歌所在的唱片集 ] [ar:歌词作者 ] [by:本LRC文件的创建者 ] [offset:+/- 以毫秒为单位整体时间戳调整,+增加,-减小 ] [re:创建此LRC文件 ...

  4. android音乐播放器之在线播放功能的实现

    转发请注明出处:http://blog.csdn.net/qq_28055429/article/details/51327171 前言:由于最近在做一个音乐播放器,需实现在线播放功能的实现,故而找了 ...

  5. android 音乐播放器----歌词在线下载

    本文来自CSDN丹丹博客,转载请必须注明出处: http://blog.csdn.net/dany1202/archive/2011/06/09/6533513.aspx 使用百度的歌词API,如: ...

  6. 【android】音乐播放器之设计思路

    学习Android有一个多月,看完了<第一行代码>以及mars老师的第一期视频通过音乐播放器小项目加深对知识点的理解.从本文开始,将详细的介绍简单仿多米音乐播放器的实现,以及网络解析数据获 ...

  7. 【android】音乐播放器之数据存储总结

    学习Android有一个多月,看完了<第一行代码>以及mars老师的第一期视频通过音乐播放器小项目加深对知识点的理解.从本文开始,将详细的介绍简单仿多米音乐播放器的实现,以及网络解析数据获 ...

  8. 【android】音乐播放器之service服务设计

    学习Android有一个多月,看完了<第一行代码>以及mars老师的第一期视频通过音乐播放器小项目加深对知识点的理解.从本文开始,将详细的介绍简单仿多米音乐播放器的实现,以及网络解析数据获 ...

  9. 【android】音乐播放器之UI设计的点点滴滴

    学习Android有一个多月,看完了<第一行代码>以及mars老师的第一期视频通过音乐播放器小项目加深对知识点的理解.从本文开始,将详细的介绍简单仿多米音乐播放器的实现,以及网络解析数据获 ...

最新文章

  1. 什么是A记录、MX记录、CNAME记录
  2. Machine Learning | (10) 回归算法-岭回归
  3. Python中bitmap数据结构的构造和使用
  4. 世界级Oracle专家权威力作
  5. linux tar 参数 cvf xvf cvzf zxvf 区别
  6. w3c的ajax操作函数,关于ajax的使用方法_例题、ajax的数据处理
  7. 求对一组数据进行排名的算法
  8. 推荐一个配置linux服务的网站
  9. k-shingles和MinHash优秀文章保存
  10. 状态码202_至少 10 个 HTTP 状态码
  11. Ext.state.Manager.setProvider(new Ext.state.CookieProvider())
  12. Leetcode每日一题:56. I. 数组中数字出现的次数
  13. Flutter进阶—实现动画效果(七)
  14. 内存碎片过高优化的功能和原理
  15. win7开机有画面进系统黑屏怎么办
  16. arcgis发布路网路径规划服务
  17. SSM毕设项目车辆维修管理系统m97p7(java+VUE+Mybatis+Maven+Mysql)
  18. VR火灾隐患排查,模拟多种火灾场景
  19. 【Pigeon源码阅读】RPC底层通信实现原理(八)
  20. 数据可视化8_数据分析的一般流程

热门文章

  1. javascript之jQuery:一个轻松编写js的库
  2. 如何生成餐桌专属二维码
  3. 双网卡实现同时连通两个网络
  4. 无人机数据处理工作站完美配置方案
  5. Redis集群方案及实现
  6. 笔记本电脑分屏显示设置
  7. 数据结构和算法(第九章哈希表)
  8. Activiti流程定义缓存源码分析8-流程缓存自定义原理
  9. 华为全栈云如沐春风 AI成点睛之笔
  10. 一把王者的时间就写完了一个nginx的web集群项目