javafx音乐播放器----歌词同步实时显示(包含获取酷我歌词方式,歌词同步方法)
- 首先我是爬蟲獲取的酷我的音源,因此歌詞也是通過爬蟲獲取的,下面這個方法可以獲取到歌曲對應的歌詞信息。簡單說下,在搜索歌曲之后會返回一個歌曲列表,查看源代碼是包含在li標簽里面的,這個li標簽里面就有請求播放頁面的地址,拿到這個地址請求單個歌曲頁面播放的時候響應的html里面的js就包含了歌詞信息,然后大致是var lrcList = [{"time": "1.8","lineLyric": "九張機-(網劇《雙世寵妃》主題曲) - 葉炫清 "}這種格式的,我將每一時間段歌詞轉換為KuwoLyric對象:
 
- 獲取到了歌詞信息就是展示了,肯定是需要另外開一個線程來同步顯示歌詞的,歌詞同步采用while循環的方式:
 
? ? ?期間遇到問題如下
? ? ? ? ?1.歌曲停止再次播放的時候就會再開一個線程,這樣下去線程就會越來越多。解決方式是:(1)可以定義一個volatile 修飾的線程終止變量,當停止再播放的時候需要先結束之前的歌詞同步線程再啟動新線程,結束線程就改變一下停止變量就行了(有個缺點就是時效性不高,當歌詞線程還在睡眠中時是不會調到if里面去終止線程的,這時候切歌前面的歌詞同步線程并沒有關閉)。(2)采用中斷線程的操作,這樣線程會立即中斷,在捕獲到線程被中斷之后立馬結束當前線程。
? ? ? ? ?2.運行程序,切歌時內存和cpu占用率會成倍增加。經排查成倍增加是因為每次切歌我是直接調用顯示歌詞線程,因此每次切都會成倍增加,解決辦法仍然是第一個問題中方法,在每次切歌之前需要先終止之前歌詞線程。
? ? ? ? ?3.播放歌曲cpu占用率穩定,但是很高,經排查,由于我是通過while(true)一直比較當前播放時間和歌詞時間,來顯示歌詞的,所以cpu一直占用高,解決辦法是,先取出第一段歌詞,計算和當前播放時間差值,之后再使歌詞線程睡這個差值時間,之后再次進行判斷,這樣while就不會持續占用cpu資源。
?
顯示歌詞代碼如下(采用中斷操作):TextField是顯示歌詞的文本框,KuwoPojo是音樂實體類。先得到歌詞集合再遍歷每個小段歌詞對象,拿出時間和播放器的當前時間比較,當播放時間接近歌詞時間時候就顯示當前對應的歌詞。
public class LyricShowUtil {// 必須設置為volatile才能改變線程狀態public volatile boolean isStop = false;public Thread lyricThread;// enum PlayStatus {}public void readyLyric(TextField lrcText, KuwoPojo nowMusic, MediaPlayer player) {// 得到每段歌詞組成的列表List<KuwoLyric> lyric = KuwoMusic.obj.getLyric(nowMusic.getLabel());System.out.println("歌詞列表:" + lyric);lrcText.setText("**********wait**********");for (KuwoLyric kuwoLyric : lyric) {String time = kuwoLyric.getTime();while (true) {if (this.isStop) {System.out.println("**********結束歌詞顯示線程**********");return;} ;Double temp=Double.valueOf(time).doubleValue()*1000- player.getCurrentTime().toMillis();//單位是毫秒ms// 設置歌詞顯示精度if ( temp< 0.1) {System.out.println("======顯示歌詞" + Double.valueOf(time).doubleValue() + " "+ player.getCurrentTime().toSeconds());System.out.println(lrcText + " " + kuwoLyric + " " + kuwoLyric.getLineLyric());lrcText.setText(kuwoLyric.getLineLyric());break;}else {try {TimeUnit.MILLISECONDS.sleep(temp.longValue());} catch (InterruptedException e) {System.out.println("歌詞顯示線程readyLyric出錯");e.printStackTrace();}}}}}public void showLyricInfo(TextField lrcText, KuwoPojo nowMusic, MediaPlayer player) {// 之前可能中斷過線程,因此每次調用需要重新設值this.isStop = false;lyricThread = new Thread(() -> {try {readyLyric(lrcText, nowMusic, player);} catch (InterruptedException e) {System.out.println("歌詞顯示線程被中斷 " + e.getMessage());return;}}, "歌詞展示線程");lyricThread.start();} }點擊播放按鈕觸發的方法如下:該方法在Controller里面,selectMusic是當前選中的音樂,nowMusic是當前播放的音樂,player是MediaPlayer對象。
public void play(ActionEvent event) {if (player!=null&&selectMusic == nowMusic) {// 暫停/停止 再播放同一首歌的時候if (player.getStatus().toString().equals("STOPPED")) {//停止再播放 同一首歌lyricShowUtil.lyricThread.interrupt();// 停止之前歌詞同步線程lyricShowUtil.showLyricInfo(lrcText, nowMusic, player);}else {//暫停-->播放System.out.println("暫停---》播放");}} if (player == null||selectMusic!=nowMusic) {// 第一次播放的時候 or 切歌,播放當前選中的歌曲if (player==null) {lyricShowUtil = new LyricShowUtil();}else {lyricShowUtil.lyricThread.interrupt();// 停止之前歌詞同步線程player.dispose();}// 獲取當前選中的labelnowMusic = musicList.getSelectionModel().getSelectedItem();Media media = new Media(nowMusic.getMp3PlayUrl());player = new MediaPlayer(media);System.out.println("====正在播放=======" + nowMusic);lyricShowUtil.showLyricInfo(lrcText, nowMusic, player);}完整音樂播放器代碼請見github:https://github.com/MrLawrenc/MarsTools? 在music包里面有完整的音樂播放器代碼
總結
以上是生活随笔為你收集整理的javafx音乐播放器----歌词同步实时显示(包含获取酷我歌词方式,歌词同步方法)的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 南京中型及以上IT企业名录
 - 下一篇: Unicode简介