百度音乐盒提供了一个便捷的API可以拿来访问一些音乐资源,开发者通过访问指定格式的url可以拿到返回的数据,这个数据可以是json或者xml,这里面包含了歌曲的信息。完整的API各种访问格式是非常丰富的,参见http://www.cnblogs.com/liuying1995/p/5704176.html。这里我们只实现查询关键字,得到返回的歌曲列表和百度定义的歌曲的id,然后再使用这个id访问,再从返回的数据中得到歌曲和歌词的地址,接下来就可以顺利完成歌曲的播放和下载了。-------另外,本文中还提供了一个动态显示歌词的自定义view和读取歌词文件的工具类。
2.在查询方法中访问URL并得到返回的json,传入解析json的方法。这里面的url字符串格式参见开头提到的网站,可以看到字符串最后的参数query=我们传入的查询数据。
4.展示歌词的自定义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; } }