实现功能:
实现网络音乐搜索功能
实现网络音乐下载功能
下载好的音乐目前不在播放器内,可以通过文件浏览器查看。
后续将博文,将实现歌词和下载音乐扫描功能。
实现效果如图:
实现代码如下:
NetMusicListFragment如下:
package com.iwanghang.drmplayer;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Toast;import com.iwanghang.drmplayer.adapter.NetMusicListAdapter;
import com.iwanghang.drmplayer.utils.AppUtils;
import com.iwanghang.drmplayer.utils.Constant;
import com.iwanghang.drmplayer.utils.SearchMusicUtils;
import com.iwanghang.drmplayer.vo.SearchResult;import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;import java.io.IOException;
import java.util.ArrayList;public class NetMusicListFragment extends Fragment implements OnItemClickListener,OnClickListener {private ListView listView_net_music;private LinearLayout load_layout;private LinearLayout ll_search_btn_container;//查询按钮的容器private LinearLayout ll_search_container;//查询按钮的容器private ImageButton ib_search_btn;private EditText et_search_content;private NetMusicListAdapter netMusicListAdapter;//存放 网络音乐 的集合private ArrayList<searchresult> searchResults = new ArrayList<searchresult>();private int page = 1;//搜索音乐的页码private MainActivity mainActivity;//private boolean isPause = false;//歌曲播放中的暂停状态private int position = 0;//当前播放的位置,提供给PlayActivity//onAttach(),当fragment被绑定到activity时被调用(Activity会被传入.).@Overridepublic void onAttach(Context context) {super.onAttach(context);//mainActivity = (MainActivity) context;mainActivity = (MainActivity) getActivity();}public static NetMusicListFragment newInstance() {NetMusicListFragment net = new NetMusicListFragment();return net;}@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {//UI组件初始化View view = inflater.inflate(R.layout.net_music_list_layout,null);//itemlistView_net_music = (ListView) view.findViewById(R.id.listView_net_music);//findViewByIdload_layout = (LinearLayout) view.findViewById(R.id.load_layout);ll_search_btn_container = (LinearLayout) view.findViewById(R.id.ll_search_btn_container);ll_search_container = (LinearLayout) view.findViewById(R.id.ll_search_container);ib_search_btn = (ImageButton) view.findViewById(R.id.ib_search_btn);et_search_content = (EditText) view.findViewById(R.id.et_search_content);//Item点击事件监听listView_net_music.setOnItemClickListener(this);//按钮点击事件监听ll_search_btn_container.setOnClickListener(this);ib_search_btn.setOnClickListener(this);loadNetData();//加载网络音乐return view;}private void loadNetData() {load_layout.setVisibility(View.VISIBLE);//加载网络音乐的异步任务new LoadNetDataTask().execute(Constant.MIGU_CHINA);}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.ll_search_btn_container:ll_search_btn_container.setVisibility(View.GONE);ll_search_container.setVisibility(View.VISIBLE);break;case R.id.ib_search_btn://搜索事件searchMusic();break;}}//搜索音乐private void searchMusic() {//隐藏键盘AppUtils.hideInputMethod(et_search_content);ll_search_btn_container.setVisibility(View.VISIBLE);ll_search_container.setVisibility(View.GONE);//获取输入的文字String key = et_search_content.getText().toString();if (TextUtils.isEmpty(key)){//如果为空,则,Toast提示Toast.makeText(mainActivity,"请输入歌手或歌词",Toast.LENGTH_SHORT).show();return;}load_layout.setVisibility(View.VISIBLE);//加载layout效果.显示//填充item 使用SearchMusicUtils搜索音乐工具类,并,使用观察者设计模式,自己回调,自己监听SearchMusicUtils.getInstance().setListener(new SearchMusicUtils.OnSearchResultListener(){@Overridepublic void onSearchResult(ArrayList<searchresult> results) {ArrayList<searchresult> sr = netMusicListAdapter.getSearchResults();sr.clear();sr.addAll(results);netMusicListAdapter.notifyDataSetChanged();//更新网络音乐列表load_layout.setVisibility(View.GONE);}}).search(key,page);}//列表项的单击事件@Overridepublic void onItemClick(AdapterView<!--?--> parent, View view, int position, long id) {if (position >= netMusicListAdapter.getSearchResults().size() || position < 0) return;showDownloadDialog(position);}//下载弹窗private void showDownloadDialog(final int position){DownloadDialogFragment downloadDialogFragment = DownloadDialogFragment.newInstance(searchResults.get(position));downloadDialogFragment.show(getFragmentManager(),"download");}//加载网络音乐的异步任务//Android1.5提供了 工具类 android.os.AsyncTask,它使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。class LoadNetDataTask extends AsyncTask<string,integer,integer>{//onPreExecute方法用于在执行后台任务前做一些UI操作@Overrideprotected void onPreExecute() {super.onPreExecute();load_layout.setVisibility(View.VISIBLE);//加载layout.显示listView_net_music.setVisibility(View.GONE);//item.隐藏searchResults.clear();//搜索结果.清理}//doInBackground方法内部执行后台任务,不可在此方法内修改UI@Overrideprotected Integer doInBackground(String... params) {String url = params[0];try {//使用Jsoup组件请求网络,并解析音乐数据Document doc = Jsoup.connect(url).userAgent(Constant.USER_AGENT).timeout(6000).get();System.out.println("start**********doc**********doc**********doc**********");System.out.println(doc);System.out.println(" end **********doc**********doc**********doc**********");//从doc分析以上html代码;把所有span标签下fl song_name查找出来,存在songTitles集合中;即,歌名集合;//从doc分析以上html代码;把所有span标签下fl singer_name.mr5t查找出来,存在artists集合中;即,歌手集合;Elements songTitles = doc.select("span.fl.song_name");System.out.println(songTitles);Elements artists = doc.select("span.fl.singer_name.mr5");System.out.println(artists);for (int i=0;i<songtitles.size();i++){ :="" searchresult="">半壶纱<,半壶纱就是a链接的内容);即,最终的歌名;Elements urls = songTitles.get(i).getElementsByTag("a");//System.out.println("@urls : " + urls);searchResult.setUrl(urls.get(0).attr("href"));//设置最终的urlsearchResult.setMusicName(urls.get(0).text());//设置最终的歌名//a链接,存在urls集合中;即,歌曲url集合;Elements artistElements = artists.get(i).getElementsByTag("a");//System.out.println("@artistElements : " + artistElements);searchResult.setArtist(artistElements.get(0).text());//设置最终的歌手searchResult.setAlbum("华语榜");//设置最终的专辑System.out.println("@searchResult : " + searchResult);searchResults.add(searchResult);//把最终的所有信息,添加到集合}System.out.println("@searchResults : " + searchResults);//System.out.println("@songTitles.size() : " + searchResults.size());} catch (IOException e) {e.printStackTrace();return -1;}return 1;}//onPostExecute方法用于在执行完后台任务后更新UI,显示结果@Overrideprotected void onPostExecute(Integer result) {super.onPostExecute(result);if (result==1){netMusicListAdapter = new NetMusicListAdapter(mainActivity,searchResults);//System.out.println(searchResults);listView_net_music.setAdapter(netMusicListAdapter);listView_net_music.addFooterView(LayoutInflater.from(mainActivity).inflate(R.layout.footviwe_layout,null));}load_layout.setVisibility(View.GONE);listView_net_music.setVisibility(View.VISIBLE);}}}
DownloadDialogFragment如下:
package com.iwanghang.drmplayer;import android.app.AlertDialog;
import android.app.Dialog;
import android.support.v4.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.widget.Toast;import com.iwanghang.drmplayer.utils.DownloadUtils;
import com.iwanghang.drmplayer.vo.SearchResult;/*** Created by iwanghang on 16/5/3.* DownloadDialogFargment*/
public class DownloadDialogFragment extends DialogFragment {private SearchResult searchResult;//当前要下载的歌曲对象private MainActivity mainActivity;public static DownloadDialogFragment newInstance(SearchResult searchResult){DownloadDialogFragment downloadDialogFragment = new DownloadDialogFragment();downloadDialogFragment.searchResult = searchResult;return downloadDialogFragment;}private String[] items;@Overridepublic void onAttach(Context context) {super.onAttach(context);mainActivity = (MainActivity) getActivity();//items = new String[]{"下载","取消"};items = new String[]{getString(R.string.download),getString(R.string.cancel)};}//创建对话框的事件方法@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {final AlertDialog.Builder builder = new AlertDialog.Builder(mainActivity);builder.setCancelable(true);//返回键可以取消builder.setItems(items,new DialogInterface.OnClickListener(){@Overridepublic void onClick(DialogInterface dialog, int which) {switch (which) {case 0://执行下载downloadMusic();break;case 1://取消dialog.dismiss();break;}}});return builder.show();}//下载音乐private void downloadMusic() {Toast.makeText(mainActivity, "正在下载:" + searchResult.getMusicName(), Toast.LENGTH_SHORT).show();DownloadUtils.getsInstance().setListener(new DownloadUtils.OnDownloadListener() {@Overridepublic void onDowload(String mp3Url) { //下载成功Toast.makeText(mainActivity, "下载成功", Toast.LENGTH_SHORT).show();}@Overridepublic void onFailed(String error) { //下载失败Toast.makeText(mainActivity, error, Toast.LENGTH_SHORT).show();}}).download(searchResult);}}
DownloadUtils如下:
package com.iwanghang.drmplayer.utils;import android.os.Environment;
import android.os.Handler;
import android.os.Message;import com.iwanghang.drmplayer.vo.SearchResult;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import javax.xml.parsers.ParserConfigurationException;/*** Created by iwanghang on 16/5/3.* 网络音乐下载工具类*/
public class DownloadUtils {private static final String DOWNLOAD_URL = "/download?_o=%2Fsearch%2Fsong";private static final int SUCCESS_LRC = 1;//下载歌词成功private static final int FAILED_LRC = 2;//下载歌词失败private static final int SUCCESS_MP3 = 3;//下载歌曲成功private static final int FAILED_MP3 = 4;//下载歌曲失败private static final int GET_MP3_URL = 5;//获取音乐下载地址成功private static final int GET_FAILED_MP3_URL = 6;//获取音乐下载地址失败private static final int MUSIC_EXISTS = 7;//下载时,音乐已存在private static DownloadUtils sInstance;private OnDownloadListener mListener;private ExecutorService mThreadPool;/***设置回调监听器对象* @param mListener* @return*/public DownloadUtils setListener(OnDownloadListener mListener){this.mListener = mListener;return this;}//获取下载工具的实例public synchronized static DownloadUtils getsInstance(){if (sInstance == null){try {sInstance = new DownloadUtils();} catch (ParserConfigurationException e) {e.printStackTrace();}}return sInstance;}/*** 下载的具体业务方法* @throws ParserConfigurationException*/private DownloadUtils() throws ParserConfigurationException{mThreadPool = Executors.newSingleThreadExecutor();}public void download(final SearchResult searchResult){final Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch (msg.what){case SUCCESS_LRC:if (mListener != null) mListener.onDowload("歌词下载成功");break;case FAILED_LRC:if (mListener != null) mListener.onFailed("歌词下载失败");break;case GET_MP3_URL:System.out.println("GET_MP3_URL:"+msg.obj);downloadMusic(searchResult,(String)msg.obj,this);break;case GET_FAILED_MP3_URL:if (mListener != null) mListener.onFailed("下载失败,该歌曲为收费或VIP类型");break;case SUCCESS_MP3:if (mListener != null) mListener.onDowload(searchResult.getMusicName()+"已经下载");String url = Constant.MIGU_URL + searchResult.getUrl();System.out.println("download lrc:"+url);downloadLRC(url,searchResult.getMusicName(),this);break;case FAILED_MP3:if (mListener != null) mListener.onFailed(searchResult.getMusicName()+"下载失败");break;case MUSIC_EXISTS:if (mListener != null) mListener.onFailed("音乐已存在");break;}}};getDownloadMusicURL(searchResult,handler);}//获取下载音乐的URLprivate void getDownloadMusicURL(final SearchResult searchResult, final Handler handler) {mThreadPool.execute(new Runnable() {@Overridepublic void run() {//https://music.xxxx.cn/#/album/1003215276//1003215279//https://music.xxxx.cn/order/1003215279/down/self/P2Z3Y12L1N2/3/001002A/1003215279System.out.println("searchResult.getUrl() = " + searchResult.getUrl());String[] aa = searchResult.getUrl().split("/");String sn = aa[5];System.out.println("歌曲编号 = " + sn);String url = Constant.MIGU_DOWN_HEAD + sn + Constant.MIGU_DOWN_FOOT;System.out.println("下载页面url = " + url);try {Document doc = Jsoup.connect(url).userAgent(Constant.USER_AGENT).timeout(6000).get();//System.out.println(doc);System.out.println("doc.toString() = " + doc.toString());String[] bb = doc.toString().split("song");//把 下载页面源码 按照"song"分割for (int i=0;i<bb.length;i++){ i="" if="">0){System.out.println("mp3?msisdn = " + bb[i]);String initMp3Url = bb[i];//initMp3Url 初始Mp3下载链接,如下//mp3?msisdn = ":"https://tyst.xxxx.cn/public/ringmaker01/10月31日中文延期/文件/全套格式/9000首/全曲试听/Mp3_128_44_16/一起走过的日子-刘德华.mp3?msisdn\u003d7b609763f0ff","String[] arrayHttp = initMp3Url.split("http");//把 初始Mp3下载链接 按照"http"分割String[] arrayMp3 = arrayHttp[1].split(".mp3");//把 arrayHttp 按照".mp3"分割String result = "http" + arrayMp3[0] + ".mp3";//把分割去掉的"http"和".mp3",组合回来System.out.println("result");//String result = "https://tyst.xxxx.cn/public/ringmaker01/10月31日中文延期/文件/全套格式/9000首/全曲试听/Mp3_128_44_16/一起走过的日子-刘德华.mp3";Message msg = handler.obtainMessage(GET_MP3_URL,result);msg.sendToTarget();}}} catch (IOException e) {e.printStackTrace();handler.obtainMessage(GET_FAILED_MP3_URL).sendToTarget();}}});}//下载歌词private void downloadLRC(final String url, final String musicName,final Handler handler){mThreadPool.execute(new Runnable() {@Overridepublic void run() {try {Document doc = Jsoup.connect(url).userAgent(Constant.USER_AGENT).timeout(6000).get();Elements lrcTag = doc.select("p.lyric-content");String lrcURL = lrcTag.attr("data-lrclink");//System.out.println(lrcURL);File lrcDirFile = new File(Environment.getExternalStorageDirectory() + Constant.DIR_LRC);if (!lrcDirFile.exists()){lrcDirFile.mkdirs();}lrcURL = Constant.MIGU_URL + lrcURL;String target = lrcDirFile + "/" + musicName + ".lrc";OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url(lrcURL).build();try {Response response = client.newCall(request).execute();if (response.isSuccessful()){PrintStream ps = new PrintStream(new File(target));byte[] bytes = response.body().bytes();ps.write(bytes,0,bytes.length);ps.close();handler.obtainMessage(SUCCESS_LRC,target).sendToTarget();}}catch (IOException e){e.printStackTrace();handler.obtainMessage(FAILED_LRC).sendToTarget();}} catch (IOException e) {e.printStackTrace();}}});}//下载MP3private void downloadMusic(final SearchResult searchResult,final String url,final Handler handler){mThreadPool.execute(new Runnable() {@Overridepublic void run() {File musicDirFile = new File(Environment.getExternalStorageDirectory()+Constant.DIR_MUSIC);if (!musicDirFile.exists()){musicDirFile.mkdirs();}String mp3url = url;String target = musicDirFile + "/" + searchResult.getMusicName() + ".mp3";System.out.println(mp3url);System.out.println(target);File fileTarget = new File(target);if (fileTarget.exists()){handler.obtainMessage(MUSIC_EXISTS).sendToTarget();return;}else {//使用OkHttpClient组件OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url(mp3url).build();System.out.println(request);try {Response response = client.newCall(request).execute();if (response.isSuccessful()){PrintStream ps = new PrintStream(fileTarget);byte[] bytes = response.body().bytes();ps.write(bytes,0,bytes.length);ps.close();handler.obtainMessage(SUCCESS_MP3).sendToTarget();}} catch (IOException e) {e.printStackTrace();handler.obtainMessage(FAILED_MP3).sendToTarget();}}}});}//自定义下载事件监听器public interface OnDownloadListener {public void onDowload(String mp3Url);public void onFailed(String error);}
}
SearchMusicUtils如下:
package com.iwanghang.drmplayer.utils;import android.os.Handler;
import android.os.Message;import com.iwanghang.drmplayer.vo.SearchResult;import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import javax.xml.parsers.ParserConfigurationException;/*** Created by iwanghang on 16/4/30.* 搜索音乐工具类*/
public class SearchMusicUtils {private static final int SIZE = 20;//查询歌曲数量//private static final String URL = Constant.BAIDU_URL + Constant.BAIDU_SEARCH;//private static String URL = Constant.BAIDU_URL + Constant.BAIDU_SEARCH;private static SearchMusicUtils sInstance;private OnSearchResultListener mListener;private ExecutorService mThreadPool;//线程池public synchronized static SearchMusicUtils getInstance(){if (sInstance == null){try {sInstance = new SearchMusicUtils();} catch (ParserConfigurationException e) {e.printStackTrace();}}return sInstance;}//设置搜索事件private SearchMusicUtils() throws ParserConfigurationException{mThreadPool = Executors.newSingleThreadExecutor();//单任务线程池}public SearchMusicUtils setListener(OnSearchResultListener l){mListener = l;return this;}public void search(final String key,final int page){final Handler handler = new Handler(){//handler 用于返回数据@Overridepublic void handleMessage(Message msg) {switch (msg.what){case Constant.SUCCESS:if (mListener != null) mListener.onSearchResult((ArrayList<searchresult>)msg.obj);break;case Constant.FAILED:if (mListener != null) mListener.onSearchResult(null);break;}}};//执行线程mThreadPool.execute(new Runnable() {@Overridepublic void run() {//run方法ArrayList<searchresult> results = getMusicList(key,page);if(results == null){handler.sendEmptyMessage(Constant.FAILED);return;}handler.obtainMessage(Constant.SUCCESS,results).sendToTarget();}});}//使用Jsoup组件请求网络,并解析音乐数据private ArrayList<searchresult> getMusicList(final String key,final int page){final String start = String.valueOf((page - 1) * SIZE);ArrayList<searchresult> searchResults = new ArrayList<searchresult>();Document doc = null;String URL = null;try {//经过测试 获取页面 如果key不转码 无法打开正确连接//使用URLEncoder.encode转码,转为utf8//冰雨 转换为 %E6%B2%A1%E6%9C%89";String keyUrlEnCode = URLEncoder.encode(key, "utf8");URL = Constant.MIGU_SEARCH_HEAD + keyUrlEnCode + Constant.MIGU_SEARCH_FOOT;System.out.println(URL);doc = Jsoup.connect(URL).data("query", "Java").userAgent(Constant.USER_AGENT).timeout(60 * 1000).get();//System.out.println("~~doc = " + doc);Elements songTitles = doc.select("span.fl.song_name");System.out.println(songTitles);Elements artists = doc.select("span.fl.singer_name.mr5");System.out.println(artists);for (int i=0;i<songtitles.size();i++){ :="" a="" href="/song/121353608" searchresult="">半壶纱<,半壶纱就是a链接的内容);即,最终的歌名;Elements urls = songTitles.get(i).getElementsByTag("a");//System.out.println("@urls : " + urls);searchResult.setUrl(urls.get(0).attr("href"));//设置最终的urlsearchResult.setMusicName(urls.get(0).text());//设置最终的歌名//a链接,存在urls集合中;即,歌曲url集合;Elements artistElements = artists.get(i).getElementsByTag("a");//System.out.println("@artistElements : " + artistElements);searchResult.setArtist(artistElements.get(0).text());//设置最终的歌手searchResult.setAlbum("华语榜");//设置最终的专辑System.out.println("@searchResult : " + searchResult);searchResults.add(searchResult);//把最终的所有信息,添加到集合}System.out.println("@searchResults : " + searchResults);return searchResults;} catch (IOException e) {e.printStackTrace();}return null;}public interface OnSearchResultListener {public void onSearchResult(ArrayList<searchresult> results);}}