Android 超簡單音樂播放器(十)歌詞的實現
關於歌詞
有下面這些:
歌詞的獲取
歌詞的解析
自定義View
歌詞的獲取
歌詞的獲取分為兩種,一種是從本地一種是通過網路上提供的API獲取。我選擇的是歌詞迷的API http://api.geci.me/en/latest/ 說實話,這個API並不是很好用,因為很多歌它都無法提供歌詞。但是我懶得去找其他的啦,所以就用它好啦。
- 首先,我們要(-。-;)不知道這裡怎麼說,就說通過API找到我們需要的資料吧
和之前獲取熱門和搜尋網路歌曲一樣,因為這個API是根據歌名查詢的,所以我們需要傳入一個String name。但是這個地方需要注意,有的歌曲名可能會有空格,這樣會影響我們獲取歌詞,所以,需要把空格都去掉。總的來說這裡問題並不難..但是我弄了很久,就是因為這個空格問題,導致我每首歌曲查詢都是沒有歌詞0 0讓我產生了一種錯覺,是我使用了(line = in.readLine() )!= null 的問題(這裡摸一把淚( ▼-▼ ))
public static void requstLrcData(final String name,okhttp3.Callback callback){
OkHttpClient client = new OkHttpClient();
Log.i(TAG, "requstLrcData: "+name);
String name1 = name.trim();//去掉空格
Log.i(TAG, "requstLrcData:"+name1);
Request request = new Request.Builder()
.url("http://gecimi.com/api/lyric/"+name1)
.build();
client.newCall(request).enqueue(callback);
}
- 然後我們就要解析我們得到的資料
通過官方文件我們可以看到,會提供給我們歌詞檔案以及相應的數量。一步一步解析出自己需要的資料就好。
傳入c值表示當前需要的歌詞檔案是第幾個。這樣寫是為了當使用者發現歌詞不同時,可以切換歌詞。當沒有資料或者失敗時,返回“”。
public static String parseJOSNWithGSON(Response response ,int c){
try{
String ResponsData = response.body().string();
JSONObject jsonObject = new JSONObject(ResponsData);
int count = Integer.parseInt(jsonObject.getString("count"));
Log.i("TAG", "parseJOSNWithGSONCOUNT:"+count);
if (count>=c){
String result = jsonObject.getString("result");
JSONArray jsonArray = new JSONArray(result);
JSONObject jsonObject1 = jsonArray.getJSONObject(c-1);
String url = jsonObject1.getString("lrc");
Log.i("TAG", "parseJOSNWithGSON:1 "+url);
return url;
}else {
Log.i("TAG", "parseJOSNWithGSON: "+c);
return "";
}
}catch (Exception e){
}
return "";
}
- 最後根據解析出來的URL讀取出歌詞,準備解析
public static String getLrcFromAssets(String Url){
Log.i("first","getLrcFromAssets: "+Url);
if (Url.equals("")){
return "";
}
try {
URL url=new URL(Url);
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
conn.setDoInput(true);
conn.setRequestMethod("GET");
InputStream input=conn.getInputStream();
BufferedReader in=new BufferedReader(new InputStreamReader(input));
String line = "" ;
String result = "";
while ((line = in.readLine() )!= null){//逐行讀取
if (line.trim().equals(""))
continue;
result += line + "\r\n";
Log.i("first","getLrcFromAssets: "+result);
}
Log.i("total","getLrcFromAssets: "+result);
return result;
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
到這裡我們的歌詞就讀取出來(此處應有掌聲)~
歌詞的解析
我們一般的歌詞檔案分為兩種。
第一種:
[ti:流浪的小孩]
[ar:伊能靜]
[al:流浪的小孩]
[00:01]流浪的小孩
[00:05]專輯:流浪的小孩
[00:07] 唱: 伊能靜
[00:08]流浪的小孩 淚為自己流
[00:15]流浪的小孩 笑發自心中
[00:22]流浪的小孩 少年多揮霍
[00:28]心比世界還寬容
[00:34]MUSIC
[01:06]不斷要往那裡走 找到一個地方屬於我
[01:14]不需要勉強虛偽 心像風一樣自由
[01:22]告別金色和無知 不希望自己變得太成熟
[01:30]成人的謊言太多 夢也漸漸被現實奪走
[01:38]我要出去走一走 年少的心有勇氣追求
[01:46]看世界多開闊 天能夠有多大 夢多難求
[01:54]我要出去走一走 孤單的生活會更快樂
[02:02]也許會有挫折 但這是我的選擇
[02:10]流浪的小孩 淚為自己流
第二種:
[00:00.00]海闊天空
[00:15.00]專輯:樂與怒
[00:18.00] [01:43.00][00:19.00]今天我寒夜裡看雪飄過
[01:49.00][00:25.00]懷著冷卻了的心窩飄遠方
[01:55.00][00:31.00]風雨裡追趕
[01:58.00][00:34.00]霧裡分不清影蹤
[02:05.00][00:40.00]可會變(誰沒在變)
[00:50.00]從沒有放棄過心中的理想
[00:56.00]一剎那恍惚
[01:05.00]心裡愛(誰明白我)
第一種只有分和秒,而第二種還包含了毫秒。除此之外,有的時間會對應多句歌詞。所以我們在解析前就需要把時間都分開,最後按照時間大小排序 。
- 新建一個介面
public interface ILrcBulider {
List<LrcRow> getLrcRows(String rawLrc);
}
- 然後是解析歌詞構造器
實現上面寫的那個介面,得到一個按時間從小到大歌詞集合。
public class DefaultLrcBulider implements ILrcBulider {
@Override
public List<LrcRow> getLrcRows(final String rawLrc) {
Log.i(TAG,"getLrcRows by rawString"+rawLrc+"");
if (rawLrc == null || rawLrc.length() == 0){
Log.i(TAG,"getLrcRows rawLrc null or empty");
return null;
}
StringReader reader = new StringReader(rawLrc);
BufferedReader bufferedReader = new BufferedReader(reader);
String line = null;
List<LrcRow> rows = new ArrayList<LrcRow>();
try{
//迴圈地讀取歌詞的每一行
do{
line = bufferedReader.readLine();
Log.i(TAG,"lrc raw line: " + line);
if(line != null && line.length() > 0){
//解析每一行歌詞 得到每行歌詞的集合,因為有些歌詞重複有多個時間,就可以解析出多個歌詞行來
List<LrcRow> lrcRows = LrcRow.createRows(line);
if(lrcRows != null && lrcRows.size() > 0){
for(LrcRow row : lrcRows){//將每一個LrcRow依次新增
rows.add(row);
}
}
}
}while(line != null);
if( rows.size() > 0 ){
// 根據歌詞行的時間排序
Collections.sort(rows);
if(rows!=null&&rows.size()>0){
for(LrcRow lrcRow:rows){
Log.i(TAG, "lrcRow:" + lrcRow.toString());
}
}
}
}catch(Exception e){
Log.e(TAG,"parse exceptioned:" + e.getMessage());
return null;
}finally{
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
reader.close();
}
return rows;
}
}
}
這裡插播一下
1.什麼是Comparable介面
此介面強行對實現它的每個類的物件進行整體排序。此排序被稱為該類的自然排序 ,類的 compareTo 方法被稱為它的自然比較方法
。實現此介面的物件列表(和陣列)可以通過 Collections.sort (和 Arrays.sort
)進行自動排序。實現此介面的物件可以用作有序對映表中的鍵或有序集合中的元素,無需指定比較器。 強烈推薦(雖然不是必需的)使自然排序與
equals 一致。所謂與equals一致是指對於類 C 的每一個 e1 和 e2 來說,當且僅當
(e1.compareTo((Object)e2) == 0) 與e1.equals((Object)e2) 具有相同的布林值時,類 C
的自然排序才叫做與 equals 一致 。2.實現什麼方法
int compareTo(T o) 比較此物件與指定物件的順序。如果該物件小於、等於或大於指定物件,則分別返回負整數、零或正整數。 引數:
o - 要比較的物件。 返回:
負整數、零或正整數,根據此物件是小於、等於還是大於指定物件。 丟擲:
ClassCastException - 如果指定物件的型別不允許它與此物件進行比較。
因為我們要實現排序,所以要通過實現Comparable介面來實現。
public class LrcRow implements Comparable<LrcRow>{
public final static String TAG = "LrcRow";
/** 該行歌詞要開始播放的時間/
public String strTime;
/** 該行歌詞要開始播放的時間轉換為long型,
* 即將2分34秒14毫秒都轉為毫秒後 得到的long型值:time=02*60*1000+34*1000+14
*/
public long time;
/** 該行歌詞的內容 */
public String content;
public LrcRow(){}
public LrcRow(String strTime,long time,String content){
this.strTime = strTime;
this.time = time;
this.content = content;
}
@Override
public String toString() {
return "[" + strTime + " ]" + content;
}
/**
* 讀取歌詞的每一行內容,轉換為LrcRow,加入到集合中
*/
public static List<LrcRow> createRows(String standardLrcLine){
try{//判斷是否包含為有時間的歌詞內容(兩種歌詞檔案都進行判斷)
if (standardLrcLine.indexOf("[") == 0){
if (standardLrcLine.indexOf("]") == 6 ||standardLrcLine.indexOf("]") == 9 ){
}else{
if (standardLrcLine.indexOf(".") == 6){
}else {
return null;
}
}
}else{
return null ;
}
//[02:34.14][01:07.00]當你我不小心又想起她
//找到最後一個 ‘]’ 的位置
int lastIndexOfRightBracket = standardLrcLine.lastIndexOf("]");
//歌詞內容就是 ‘]’ 的位置之後的文字 eg: 當你我不小心又想起她
String content = standardLrcLine.substring(lastIndexOfRightBracket + 1, standardLrcLine.length());
//歌詞時間就是 ‘]’ 的位置之前的文字 eg: [02:34.14][01:07.00]
/**
將時間格式轉換一下 [mm:ss.SS][mm:ss.SS] 轉換為 -mm:ss.SS--mm:ss.SS-
即:[02:34.14][01:07.00] 轉換為 -02:34.14--01:07.00-
*/
String times = standardLrcLine.substring(0,lastIndexOfRightBracket + 1).replace("[", "-").replace("]", "-");
//通過 ‘-’ 來拆分字串
String arrTimes[] = times.split("-");
List<LrcRow> listTimes = new ArrayList<LrcRow>();
for(String temp : arrTimes){
if(temp.trim().length() == 0){
continue;
}
/** [02:34.14][01:07.00]當你我不小心又想起她
*
上面的歌詞的就可以拆分為下面兩句歌詞了
[02:34.14]當你我不小心又想起她
[01:07.00]當你我不小心又想起她
*/
LrcRow lrcRow = new LrcRow(temp, timeConvert(temp), content);
listTimes.add(lrcRow);
}
return listTimes;
}catch(Exception e){
Log.e(TAG,"createRows exception:" + e.getMessage());
return null;
}
}
/**
* 將解析得到的表示時間的字元轉化為Long型
*/
private static long timeConvert(String timeString){
if(timeString.length() == 5){
timeString =timeString+":00";
}//如果為第一種歌詞檔案,則將其轉換為第二種。
//因為給如的字串的時間格式為XX:XX.XX,返回的long要求是以毫秒為單位
//將字串 XX:XX.XX 轉換為 XX:XX:XX
timeString = timeString.replace('.', ':');
//將字串 XX:XX:XX 拆分
String[] times = timeString.split(":");
// mm:ss:SS
return Integer.valueOf(times[0]) * 60 * 1000 +//分
Integer.valueOf(times[1]) * 1000 +//秒
Integer.valueOf(times[2]) ;//毫秒
}
/**
* 排序的時候,根據歌詞的時間來排序
*/
public int compareTo(LrcRow another) {
return (int)(this.time - another.time);
}
}
- 自定義View
跟著網上大神寫的。 https://github.com/ouyangpeng/android-lrc-view-oyp
主要就是根據當前時間去判斷應該讓哪一句歌詞高亮。
通過計時器每秒鐘更新當前時間,(我是放在歌詞進度條的那個計時器中的,這樣可以簡潔很多嘛)
當這個時間處於AB兩句歌詞之間時,就讓A高亮。
學習這個雖然用了很多時間,但是收穫還是很大的。
路漫漫其修遠兮,加油吧。
珍惜這段時間,可以做自己喜歡的事情。
覺得非常幸運~
[愛心]
相關文章
- Android開源音樂播放器之自動滾動歌詞Android播放器
- LRC歌詞原理和實現高仿Android網易雲音樂Android
- Android自定義View–仿QQ音樂歌詞AndroidView
- 卡拉OK歌詞原理和實現高仿Android網易雲音樂Android
- Android自定義View--仿QQ音樂歌詞AndroidView
- Linux終端音樂播放器cmus攻略: 操作歌單Linux播放器
- 網頁實現一個簡單的音樂播放器(大佬別看。(⊙﹏⊙))網頁播放器
- QQ音樂的動效歌詞是如何實踐的?
- 基於Android的音樂播放器的設計與實現Android播放器
- vue..js 編寫的簡單音樂播放器VueJS播放器
- Android 音樂播放器開發實錄(MediaSession)Android播放器Session
- Python實現多功能音樂播放器Python播放器
- HTML5 實現的音樂播放器分享HTML播放器
- Android開源線上音樂播放器——波尼音樂Android播放器
- Python抓取QQ音樂歌單並分析Python
- 如何使用 pyqt 實現 Groove 音樂播放器QT播放器
- 超簡單整合ML kit 實現聽寫單詞播報
- Flutter實戰 | 從 0 搭建「網易雲音樂」APP(七、歌詞(二))FlutterAPP
- Flutter實戰 | 從 0 搭建「網易雲音樂」APP(六、歌詞(一))FlutterAPP
- higher-music 基於Vue的支援歌單外鏈的線上網頁音樂播放器Vue網頁播放器
- Android開源音樂播放器之高仿雲音樂黑膠唱片Android播放器
- Python 爬蟲獲取網易雲音樂歌手歌詞Python爬蟲
- 10、 在QQ音樂中爬取某首歌曲的歌詞
- 如何讓音樂軟體的歌詞在touch bar上面顯示?
- Clementine for Mac - 現代音樂播放器Mac播放器
- 利用Python網路爬蟲抓取網易雲音樂歌詞Python爬蟲
- Python爬取網易雲音樂歌單歌曲Python
- 網易雲音樂推薦系統簡單實現系列
- insomnia在在哪裡聽 insomnia歌詞及中文諧音音譯歌詞全文QJ
- Android開源音樂播放器之播放器基本功能Android播放器
- Android中SharePreferences的簡單實現Android
- 雕蟲曉技(十) Android超簡單氣泡效果Android
- 不再猶豫----【諧音歌詞】
- python實現簡單猜單詞遊戲Python遊戲
- 藉助 Turbolinks 實現不間斷的網頁音樂播放器網頁播放器
- Android開源音樂播放器之線上音樂列表自動載入更多Android播放器
- 好程式設計師前端分享使用JS開發簡單的音樂播放器程式設計師前端JS播放器
- vue音樂播放器Vue播放器
- Kotlin超簡單實現StepViewKotlinView