百度音乐盒提供了一个便捷的API可以拿来访问一些音乐资源,开发者通过访问指定格式的url可以拿到返回的数据,这个数据可以是json或者xml,这里面包含了歌曲的信息。完整的API各种访问格式是非常丰富的,参见http://www.cnblogs.com/liuying1995/p/5704176.html。这里我们只实现查询关键字,得到返回的歌曲列表和百度定义的歌曲的id,然后再使用这个id访问,再从返回的数据中得到歌曲和歌词的地址,接下来就可以顺利完成歌曲的播放和下载了。-------另外,本文中还提供了一个动态显示歌词的自定义view和读取歌词文件的工具类。我直接展示我的实现思路:
1.接收输入框的输入文字并传到查询方法里。
String name = etSearch.getText().toString();
if (name.length() == 0) {
Toast.makeText(this, "请输入歌曲名称", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this,"已开始查询,请耐心等待",Toast.LENGTH_SHORT).show();
query2(name);
}
2.在查询方法中访问URL并得到返回的json,传入解析json的方法。这里面的url字符串格式参见开头提到的网站,可以看到字符串最后的参数query=我们传入的查询数据。
private void query2(final String title){
new Thread(new Runnable() {
@Override
public void run() {
try {
HttpURLConnection connection;
String finalTitle = URLEncoder.encode(title,"utf-8");
URL url = new URL("http://tingapi.ting.baidu.com/v1/restserver/ting?from=webapp_music&method=baidu.ting.search.catalogSug&format=json&callback=&query="+finalTitle);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(60*1000);
connection.setReadTimeout(60*1000);
connection.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String s;
if ((s=reader.readLine())!=null)
doJson(s);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
3.在解析方法中最终取得歌曲的名称,艺术家,地址,歌词地址信息,json解析就不具体展开了,然后我把这些数据封装在自定义的Song对象里。(方法中调用了两个方法,分别是获取歌曲地址和歌词地址,在下面会展示,这是因为获取这两个数据需要用得到的歌曲的id再一次访问)。
//解析返回的json
public Song doJson(String json){
Song song = null;
JSONObject jsonObject = null;
list.clear();//清空原有的歌曲数组
try {
//去掉括号
json = json.replace("(","");
json = json.replace(")","");
jsonObject = new JSONObject(json);
JSONArray array = new JSONArray(jsonObject.getString("song"));
for (int i=0;i<array.length();i++){
JSONObject object = array.getJSONObject(i);
String songname = object.getString("songname");
String artistname = object.getString("artistname");
String songid = object.getString("songid");
String adress = getAdress(songid);
Song song1 = new Song(songname,artistname,adress,0);
song1.setLrcPath(getLrcAdress(songid));
list.add(i,song1);
Log.v("tag",songname+" "+artistname+" "+songid);
//列表更新
Message msg = new Message();
msg.what = 1;
handler.sendMessage(msg);
}
} catch (JSONException e) {
e.printStackTrace();
}
return song;
}
public String getAdress(final String songid){
new Thread(new Runnable() {
@Override
public void run() {
try {
HttpURLConnection connection;
//URL url = new URL("http://api.5288z.com/weixin/musicapi.php?q="+finalTitle);
URL url = new URL("http://ting.baidu.com/data/music/links?songIds="+songid);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(60*1000);
connection.setReadTimeout(60*1000);
connection.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String s;
if ((s=reader.readLine())!=null){
s = s.replace("\\","");//去掉\\
try {
JSONObject object = new JSONObject(s);
JSONObject object1 = object.getJSONObject("data");
JSONArray array = object1.getJSONArray("songList");
JSONObject object2 = array.getJSONObject(0);
adress = object2.getString("songLink");
Log.v("tagadress",adress);
} catch (JSONException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return adress;
}
//获取歌词地址
public String getLrcAdress(final String songid){
new Thread(new Runnable() {
@Override
public void run() {
try {
HttpURLConnection connection;
//URL url = new URL("http://api.5288z.com/weixin/musicapi.php?q="+finalTitle);
URL url = new URL("http://ting.baidu.com/data/music/links?songIds="+songid);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(60*1000);
connection.setReadTimeout(60*1000);
connection.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String s;
if ((s=reader.readLine())!=null){
s = s.replace("\\","");//去掉\\
Log.v("tag","------"+s);
try {
JSONObject object = new JSONObject(s);
JSONObject object1 = object.getJSONObject("data");
JSONArray array = object1.getJSONArray("songList");
JSONObject object2 = array.getJSONObject(0);
LrcAdress = object2.getString("lrcLink");
Log.v("tag","888888lrc"+ LrcAdress);
} catch (JSONException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return LrcAdress;
}
4.展示歌词的自定义view(转):这里传入了一个自定义的歌词类,是把每一行歌词作为一个对象,其中有歌词内容和歌词开始时间这两个值。
package com.example.one.newmusicplayer.ui;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
import com.example.one.newmusicplayer.item.LrcOne;
import java.util.ArrayList;
import java.util.List;
/**
* Created by lenovo on 2016/10/27.
* 显示歌词的自定义view
*/
public class LrcView extends TextView {
private float width; //歌词视图宽度
private float height; //歌词视图高度
private Paint currentPaint; //当前歌词画笔
private Paint notCurrentPaint; //非当前歌词画笔
private float textHeight = 45; //每一行高度
private float textSize = 35; //每一行非当前文字的大小
private int index = 0; //list集合下标
private List<LrcOne> list = new ArrayList<>();
public LrcView(Context context) {
super(context);
init();
}
public LrcView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
setFocusable(true); //设置可对焦
//高亮部分
currentPaint = new Paint();
currentPaint.setAntiAlias(true); //设置抗锯齿,让文字美观饱满
currentPaint.setTextAlign(Paint.Align.CENTER);//设置文本对齐方式
//非高亮部分
notCurrentPaint = new Paint();
notCurrentPaint.setAntiAlias(true);
notCurrentPaint.setTextAlign(Paint.Align.CENTER);
}
/**
* 绘画歌词
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(canvas == null) {
return;
}
//设置字体的大小颜色样式以及绘制出来的画笔
currentPaint.setColor(Color.argb(210, 251, 0, 0));
notCurrentPaint.setColor(Color.argb(140, 0, 0, 0));
currentPaint.setTextSize(40);
currentPaint.setTypeface(Typeface.SERIF);
notCurrentPaint.setTextSize(textSize);
notCurrentPaint.setTypeface(Typeface.DEFAULT);
try {
setText("");
canvas.drawText(list.get(index).getLrcStr(), width / 2, height / 2, currentPaint);
float tempY = height / 2;
//画出本句之前的句子
for(int i = index - 1; i >= 0; i--) {
//向上推移
tempY = tempY - textHeight;
canvas.drawText(list.get(i).getLrcStr(), width / 2, tempY, notCurrentPaint);
}
tempY = height / 2;
//画出本句之后的句子
for(int i = index + 1; i < list.size(); i++) {
//往下推移
tempY = tempY + textHeight;
canvas.drawText(list.get(i).getLrcStr(), width / 2, tempY, notCurrentPaint);
}
} catch (Exception e) {
setText("");
}
}
/**
* 当view大小改变的时候调用的方法
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
this.width = w;
this.height = h;
}
public void setIndex(int index) {
this.index = index;
}
public void setmLrcList(List<LrcOne> mLrcList) {
this.list = mLrcList;
}
}
5.读取歌词文件的工具类,读取后封装在一个歌词类的数组里。
package com.example.one.newmusicplayer.tools;
import android.util.Log;
import android.widget.Toast;
import com.example.one.newmusicplayer.item.LrcOne;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
/**
* Created by lenovo on 2016/10/27.
* 读取歌词并将其拆成一个个歌词类的工具类
*/
public class LrcDeal {
public List<LrcOne> getList() {
return list;
}
private List<LrcOne> list = new ArrayList<>();
//读取歌词并返回一个装满歌词对象的list
//读取网络歌词文件的方法
public List<LrcOne> readIntnetLrc(String path){
InputStream inputStream = null;
try {
URL url = new URL(path);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(60*1000);
connection.setReadTimeout(60*1000);
inputStream = connection.getInputStream();
} catch (Exception e) {
e.printStackTrace();
}
StringBuilder stringBuilder = new StringBuilder();
//创建一个文件输入流
try {
//创建一个文件输入流对象
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
String s = "";
while((s = br.readLine()) != null) {
s = s.replace("[", "");
s = s.replace("]", "@");
//分离“@”字符
String splitLrcData[] = s.split("@");
LrcOne lrcOne = new LrcOne();
if(splitLrcData.length > 1) {
lrcOne.setLrcStr(splitLrcData[1]);
//处理歌词取得歌曲的时间
int lrcTime = time2Str(splitLrcData[0]);
lrcOne.setLrcTime(lrcTime);
//添加进列表数组
list.add(lrcOne);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
stringBuilder.append("木有歌词文件,赶紧去下载!...");
} catch (IOException e) {
e.printStackTrace();
stringBuilder.append("木有读取到歌词哦!");
}
return list;
}
//对时间字符串进行处理
public int time2Str(String timeStr) {
timeStr = timeStr.replace(":", ".");
timeStr = timeStr.replace(".", "@");
String timeData[] = timeStr.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;
}
}