音乐播放器功能的实现,歌词lrc显示,播放过程中来电

时间:2021-12-25 10:13:01
原文地址:http://blog.sina.com.cn/s/blog_afb547c60101hjfd.html  5.1 音乐播放器功能的实现。(社区ID:clarck)音乐播放器最主要的功能有:播放、暂停、上一首、下一首、歌曲拖拽播放、在线播放、后台播放、播放歌曲信息状态栏提醒、搜索歌曲、歌词同步、扫描歌曲、换肤、设置铃声、歌曲信息、下载歌曲、均衡器调节、来电时音乐播放器的音量调节等等。音乐播放器的功能就是前台要实现什么功能通过接口语言告诉后台,具体怎么实现让service去实现,以达到前台和服务各自实现自己的功能,又能相结合通信的目的。其中,网络搜索要用到xml解析,换肤主要是改变background,以下是一些名词的解释:Service:要实现后台播放就要结合到Android中的服务AndroidInterfaceDefinitionLanguage:跨进程通信机制AIDL(接口描述语言)NotificationManager:通知管理器Handle:消息机制TelephonyManager:手机来电接收器管理RingtoneManager:铃声管理器WindowManager:屏幕亮度调节service中通过Binder来实现和IPlayback绑定 5.1.1 AIDL的使用:以aidl为文件结尾,定义一些供前台调用的接口,接口全部在service中实现。以达到和service进行通信的目的,实现跨进程调用。IPlayback.aidlinterface IPlayback {//开始播放void start();//暂停播放void pause();//停止播放void stop();//释放资源void release();//上一首void previous();//下一首void next() ;//获取正在播放的音乐的IDint getId() ;//获取正在播放的音乐的标题java.lang.String getTitle();//获取正在播放的音乐的艺术家 java.lang.String getArtist() ;//获取正在播放的音乐的专辑java.lang.String getAlbum() ;//获取当前播放的位置int getDuration();//获取当前播放的时间int getTime();//拖放void seek(int time);//判断是否正在播放boolean isPlaying() ;} java.lang.String getArtist() ;//获取正在播放的音乐的专辑java.lang.String getAlbum() ;//获取当前播放的位置int getDuration();//获取当前播放的时间int getTime();//拖放void seek(int time);//判断是否正在播放boolean isPlaying() ;} public void start() throws RemoteException {// TODO Auto-generated method stubif(state == STOP){ //如果当前状态为STOP,调用prepare()重新播放歌曲try {player.prepare();} catch (IllegalStateException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}else if (state == PAUSE) {player.start();state=PLAYING;} public void seek(int time) throws RemoteException {// TODO Auto-generated method stubplayer.seekTo(time);}public void release() throws RemoteException {// TODO Auto-generated method stub//释放MediaPlayer对象player.release();player=null;state=IDLE;}public void previous() throws RemoteException {// TODO Auto-generated method stub//播放上一首歌曲if(!cursor.moveToPrevious())cursor.moveToLast();_play();}public void pause() throws RemoteException {// TODO Auto-generated method stub//暂停播放if (player.isPlaying()) {player.pause();state = PAUSE; }}public void next() throws RemoteException {// TODO Auto-generated method stub//播放下一首歌曲_next();if(player.isPlaying()){player.pause();state=PAUSE;}}public boolean isPlaying() throws RemoteException {// TODO Auto-generated method stubreturn player.isPlaying();}public String getTitle() throws RemoteException {// TODO Auto-generated method stub//读取正在播放歌曲的标题return cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));}public int getTime() throws RemoteException {// TODO Auto-generated method stub//获得当前的媒体时间return player.getCurrentPosition();}public int getId() throws RemoteException {// TODO Auto-generated method stubif(cursor.getPosition() == -1){return -1;}//获得当前正在播放歌曲的IDreturncursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));} public int getDuration() throws RemoteException {// TODO Auto-generated method stub//获得当前歌曲的时长return player.getDuration();}public String getArtist() throws RemoteException {// TODO Auto-generated method stub//读取正在播放歌曲的歌手信息returncursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));}public String getAlbum() throws RemoteException {// TODO Auto-generated method stub//读取正在播放歌曲的专辑returncursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));}}; @Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn binder;}@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();ContentResolver contentResolver=getContentResolver();cursor=contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTEENT_URI,null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);}@Overridepublic void onDestroy() {// TODO Auto-generated method stub super.onDestroy();if(nMgr!=null)nMgr.cancel(R.string.notification_titile);if(player!=null)player.release();}@Overridepublic void onStart(Intent intent, int startId) {// TODO Auto-generated method stubsuper.onStart(intent, startId);if(position!=-1){cursor.moveToPosition(position);_play();}} private void _play() {// TODO Auto-generated method stubStringpath=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));try {if(player==null){player=new MediaPlayer();player.setOnCompletionListener(completionListener);player.setOnPreparedListener(preParedListener);player.setOnErrorListener(errorListener);}else{player.reset();}player.setDataSource(path);player.prepare();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalStateException e) {// TODO Auto-generated catch blocke.printStackTrace(); } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}private void _next(){if(!cursor.moveToNext())cursor.moveToFirst();_play();}private OnErrorListener errorListener=new OnErrorListener() {public boolean onError(MediaPlayer mp, int what, int extra) {// TODO Auto-generated method stub_next();return true;}}; privateOnCompletionListenercompletionListener=newOnCompletionListener(){public void onCompletion(MediaPlayer mp) {// TODO Auto-generated method stubif(!cursor.moveToNext())cursor.moveToFirst();_play();}};private OnPreparedListener preParedListener= new OnPreparedListener() {public void onPrepared(MediaPlayer mp) {// TODO Auto-generated method stubplayer.start();state=PLAYING;Intent intent=new Intent(TRACK_UPDATE);sendBroadcast(intent);showNotification();}};private void showNotification() {CharSequence title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)); Notification notifi = new Notification(R.drawable.stat_sample, title,System.currentTimeMillis());//设置Intent,以便用户可以从通知列表中返回PlayingActivityPendingIntent pIntent = PendingIntent.getActivity(this, 0, newIntent(this, Main.class), 0);String message =cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));notifi.setLatestEventInfo(this, title, message, pIntent);if (nMgr == null)nMgr= (NotificationManager)getSystemService(NOTIFICATION_SERVICE);//通知用户,歌曲已经开始播放nMgr.notify(R.string.notification_titile, notifi);}} 绑定服务类:private IPlayback service;//获取连接private ServiceConnection connection=new ServiceConnection() {public void onServiceConnected(ComponentName arg0, IBinder arg1) {// TODO Auto-generated method stub//绑定成功后,获得IPlayback接口service=IPlayback.Stub.asInterface(arg1);//更新播放屏handler.sendMessage(handler.obtainMessage(UPDATE));}public void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stubservice=null;}}; if(service==null){Intent intent=new Intent(this,MusicService.class);intent.putExtra("position", position);startService(intent);intent.removeExtra("position");//绑定到服务 if(false==bindService(intent, connection,Context.BIND_AUTO_CREATE)){finish();}}1、TelephonyManager:手机来电接收器管理class IncomingSMSReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stubif (intent.getAction().equals("android.intent.action.ANSWER")) {//手机来电接收器管理TelephonyManager telephonymanager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);int callMode = Integer.parseInt(sp.getString(getString(R.string.callactionkey), "0"));//当前音量大小current = am.getStreamVolume(AudioManager.STREAM_MUSIC);switch (telephonymanager.getCallState()) {case TelephonyManager.CALL_STATE_RINGING://根据设置模式完成不同的动作switch (callMode) {case 1://暂停播放smplayer.pause();break;case 2://调低音量am.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);break;default:break;}break;case TelephonyManager.CALL_STATE_OFFHOOK: //挂机后的处理//根据设置模式完成不同的动作switch (callMode) {case 1://重新开始播放smplayer.resume();break;case 2://还原音量am.setStreamVolume(AudioManager.STREAM_MUSIC, current,0);break;default:break;}break;default:break;}}}}2、铃声管理器:RingtoneManager//来电铃声:RingtoneManager.setActualDefaultRingtoneUri(MainView.this,RingtoneManager.TYPE_RINGTONE,Uri.parse("file:////sdcard/ringtone/music.mp3");//通知铃声,RingtoneManager.setActualDefaultRingtoneUri(MainView.this,RingtoneManager.TYPE_NOTIFICATION,Uri.parse("file:////sdcard/ringtone/music.mp3");//闹钟铃声RingtoneManager.setActualDefaultRingtoneUri(MainView.this,RingtoneManager.TYPE_ALARM,Uri.parse("file:////sdcard/ringtone/music.mp3");//所有铃声RingtoneManager.setActualDefaultRingtoneUri(MainView.this,RingtoneManager.TYPE_ALL,Uri.parse("file:////sdcard/ringtone/music.mp3");3、屏幕亮度管理:WindowManagerWindowManager.LayoutParams lp = getWindow().getAttributes();lp.screenBrightness = 1.0f; //1.0f表示亮度为最亮、0.1f表示最暗getWindow().setAttributes(lp);4、打开系统设置界面:Intent intent=new Intent();intent.setComponent(new ComponentName("com.android.settings","com.android.settings.Settings"));startActivity(intent);5、进入无线网络配置界面:startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));5.2 自动下载歌词与歌词的解析。(eoe社区ID:clarck)研究了对于歌词的下载和歌词的解析,网上找了好久没有找到很好的方法,于是自己研究了一下,贡献上自己的方法,希望以后有更好的方法。5.2.1歌词下载代码:import java.io.BufferedReader;import java.io.InputStreamReader;import java.net.HttpURLConnection;import java.net.URL;import java.util.regex.Matcher;import java.util.regex.Pattern;public class HttpDownloader {private static URL url = null;public String download(String urlStr) {StringBuffer sb = new StringBuffer();String line = null;BufferedReader buffer = null;try {//创建一个URL对象url = new URL(urlStr);//创建一个Http连接HttpURLConnectionurlConn=(HttpURLConnection)url.openConnection();//使用IO流读取数据buffer = new BufferedReader(newInputStreamReader(urlConn.getInputStream()));while ((line = buffer.readLine()) != null) {sb.append(line+"\n");}} catch (Exception e) {e.printStackTrace();} finally {try {buffer.close();} catch (Exception e) {e.printStackTrace();}}return sb.toString();}public static void main(String[] args) {//这里通过拼参数进去,得到URL地址StringUrl=http://mp3.sogou.com/gecisearch.so?hl=zh-cn&query=”+MusicName+”&as=false&st=&ac=1&pf=&class=5&gecisearch.so=";HttpDownloader downloader=new HttpDownloader();String ne=downloader.download(Url);//通过正则表达式来匹配到歌词的具体下载地址Pattern pattern = Pattern.compile("((downlrc.jsp?).*(LRC歌词下载))");Matcher matcher= pattern.matcher(ne);if(matcher.find()){String wangzhi=matcher.group(0);String down=wangzhi.substring(0, wangzhi.indexOf('"'));System.out.println(ne);//拼接上hostString down_address = "http://mp3.sogou.com/"+down ;System.out.println(downloader.download(down_address));}}5.2.2 实例讲述该如何自动下载1、歌曲名为:后来直接讲MusicName改为:“后来”然后拼接进去。以下是得到的结果:[by:昨夜星辰昨夜风][00:03.21]刘若英:后来[05:16.43][00:05.26]词:施人诚曲:玉城干春编曲:王继康[04:03.05][03:37.50][02:33.36][00:12.18]后来,[04:04.79][03:39.30][02:35.11][00:14.26]我总算学会了如何去爱。[04:09.72][03:44.17][02:40.10][00:19.01]可惜你早已远去,[04:12.56][03:46.92][02:42.88][00:21.87]消失在人海。[04:15.82][03:50.10][02:46.12][00:25.14]后来,[04:17.82][03:52.09][02:48.08][00:27.05]终于在眼泪中明白,[04:22.53][03:56.77][02:52.83][00:31.93]有些人一旦错过就不再。[00:39.67]槴子花,白花瓣,[00:44.99]落在我蓝色百褶裙上。[00:51.41]“爱你!”你轻声说。[00:58.61]我低下头闻见一阵芬芳。[01:04.92]那个永恒的夜晚,[01:08.97]十七岁仲夏,[01:11.88]你吻我的那个夜晚,[01:17.98]让我往后的时光,[01:21.31]每当有感叹,[01:24.34]总想起当天的星光。[01:30.84]那时候的爱情,[01:36.46]为什么就能那样简单。[01:42.48]而又是为什么人年少时,[01:49.96]一定要让深爱的人受伤。[01:56.06]在这相似的深夜里,[02:00.32]你是否一样,[02:03.32]也在静静追悔感伤。[02:09.06]如果当时我们能不那么倔强,[02:15.86]现在也不那么遗憾。[03:25.13][02:20.91]你都如何回忆我,[03:27.92][02:23.94]带著笑或是很沉默。[03:31.14][02:27.19]这些年来有没有人能让你不寂寞。[04:29.45]永远不会再重来,[04:35.34]有一个男孩爱著那个女孩。然后将该内容保存为.“后来.lrc”文件,以供解析。2、解析歌词文件:1)保存歌词的实体类:1 public class Statement { private double time=0.0; //时间,单位为s,精确到0.01s private String lyric=""; //歌词 public double getTime() { return time; } public void setTime(double time) { this.time = time; }*/public void setTime(String time) {String str[] = time.split(":|\\.");this.time =Integer.parseInt(str[0])*60+Integer.parseInt(str[1])+Integer.parseInt(str[2])*0.01;}public String getLyric() {return lyric;}public void setLyric(String lyric) {this.lyric = lyric;}public void printLyric(){System.out.println(time+": "+lyric);}}2)具体解析类:BufferedReader bufferReader = null; //读取文件实例public String title = ""; //歌曲题目public String artist = ""; //演唱者public String album = ""; //专辑public String lrcMaker = ""; //歌词制作者Vector<Statement> statements = new Vector<Statement>(); //歌词public LrcData(String fileName) throws IOException{FileInputStream file = new FileInputStream(fileName);bufferReader=newBufferedReader(newInputStreamReader(file,"utf-8"));//将文件数据读入内存readData();}public void readData() throws IOException{statements.clear();String strLine;//循环读入所有行while(null != (strLine = bufferReader.readLine())){//判断该行是否为空行if("".equals(strLine.trim())){continue;}//判断该行数据是否表示歌名if(null == title || "".equals(title.trim())){Pattern pattern = Pattern.compile("\\[ti:(.+?)\\]");Matcher matcher = pattern.matcher(strLine);if(matcher.find()){title=matcher.group(1);continue;}else{title="未知歌名";continue;}}//判断该行数据是否表示演唱者if(null == artist || "".equals(artist.trim())){Pattern pattern = Pattern.compile("\\[ar:(.+?)\\]");Matcher matcher = pattern.matcher(strLine);if(matcher.find()){artist=matcher.group(1);continue;}else{artist="未知演唱者";continue;}}//判断该行数据是否表示专辑if(null == album || "".equals(album.trim())){Pattern pattern = Pattern.compile("\\[al:(.+?)\\]");Matcher matcher = pattern.matcher(strLine);if(matcher.find()){album=matcher.group(1);continue;}else{album="未知专辑";continue;}}//判断该行数据是否表示歌词制作者if(null == lrcMaker || "".equals(lrcMaker.trim())){Pattern pattern = Pattern.compile("\\[by:(.+?)\\]");Matcher matcher = pattern.matcher(strLine);if(matcher.find()){lrcMaker=matcher.group(1);continue;}else{lrcMaker="未知歌词制作者";continue;}}//读取并分析歌词int timeNum=0; //本行含时间个数String str[] = strLine.split("\\]"); //以]分隔for(int i=0; i<str.length; ++i){String str2[] =str[i].split("\\["); //以[分隔str[i] = str2[str2.length-1];if(isTime(str[i])){++timeNum;}}for(int i=0; i<timeNum;++i) //处理歌词复用的情况{Statement sm = new Statement();sm.setTime(str[i]);if(timeNum<str.length) //如果有歌词{sm.setLyric(str[str.length-1]);}statements.add(sm);}if(1==str.length) //处理没有歌词的情况{Statement sm = new Statement();sm.setTime(str[0]);sm.setLyric("没有歌词");statements.add(sm);}}//将读取的歌词按时间排序sortLyric();}public boolean isTime(String string){String str[] = string.split(":|\\.");if(3!=str.length){return false;}try{for(int i=0;i<str.length;++i){Integer.parseInt(str[i]);}}catch(NumberFormatException e){return false;}return true;}public void sortLyric(){for(int i=0;i<statements.size()-1;++i){int index=i;double delta=Double.MAX_VALUE;boolean moveFlag = false;for(int j=i+1;j<statements.size();++j){double sub;if(0>=(sub=statements.get(i).getTime()-statements.get(j).getTime())){continue;}moveFlag=true;if(sub<delta){delta=sub;index=j+1;}}if(moveFlag){statements.add(index, statements.elementAt(i));statements.remove(i);--i;}}}public void printLrcDate(){System.out.println("歌曲名: "+title);System.out.println("演唱者: "+artist);System.out.println("专辑名: "+album);System.out.println("歌词制作: "+lrcMaker);for(int i=0;i<statements.size();++i){statements.elementAt(i).printLyric();}}public static void main(String[] args) throws IOException {{LrcData ld = new LrcData("F://歌词//后来.lrc"); //路径\\输入文件名
ld.printLrcDate();}}
3)解析得到的结果:歌曲名:演唱者:专辑名:歌词制作:昨夜星辰昨夜风3210刘若英:后来5260词:施人诚曲:玉城干春编曲:王继康12180后来,14260我总算学会了如何去爱。19010可惜你早已远去,21870消失在人海。25140后来,27050终于在眼泪中明白,31930有些人一旦错过就不再。39670槴子花,白花瓣,44990落在我蓝色百褶裙上。51410“爱你!”你轻声说。58610我低下头闻见一阵芬芳。64920那个永恒的夜晚,68970十七岁仲夏,71880你吻我的那个夜晚,77980让我往后的时光,81310每当有感叹,84340总想起当天的星光。90840那时候的爱情,96460为什么就能那样简单。102480而又是为什么人年少时,109960一定要让深爱的人受伤。116060在这相似的深夜里,120320你是否一样,123320也在静静追悔感伤。129060如果当时我们能不那么倔强,135860现在也不那么遗憾。140910你都如何回忆我,143940带著笑或是很沉默。147190这些年来有没有人能让你不寂寞。153360后来,155110我总算学会了如何去爱。160100可惜你早已远去,162880消失在人海。166120后来,168080终于在眼泪中明白,172830有些人一旦错过就不再。205130你都如何回忆我,207920带著笑或是很沉默。211140这些年来有没有人能让你不寂寞。217500后来,219300我总算学会了如何去爱。224170可惜你早已远去,226920消失在人海。230100后来,232090终于在眼泪中明白,236770有些人一旦错过就不再。243050后来,244790我总算学会了如何去爱。249720可惜你早已远去,252560消失在人海。255820后来,257820终于在眼泪中明白,262530有些人一旦错过就不再。269450永远不会再重来,275340有一个男孩爱著那个女孩。316430词:施人诚曲:玉城干春编曲:王继康