标签:
实现功能:实现效果如图:
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会被传入.). @Override public void onAttach(Context context) { super.onAttach(context); //mainActivity = (MainActivity) context; mainActivity = (MainActivity) getActivity(); } public static NetMusicListFragment newInstance() { NetMusicListFragment net = new NetMusicListFragment(); return net; } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //UI组件初始化 View view = inflater.inflate(R.layout.net_music_list_layout,null); //item listView_net_music = (ListView) view.findViewById(R.id.listView_net_music); //findViewById load_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); } @Override public 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(){ @Override public 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); } //列表项的单击事件 @Override public 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操作 @Override protected void onPreExecute() { super.onPreExecute(); load_layout.setVisibility(View.VISIBLE);//加载layout.显示 listView_net_music.setVisibility(View.GONE);//item.隐藏 searchResults.clear();//搜索结果.清理 } //doInBackground方法内部执行后台任务,不可在此方法内修改UI @Override protected 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 searchResult = new SearchResult(); //a链接,存在urls集合中;即,歌曲url集合; //a链接,第一个a连接,href属性的值;即,最终的url; //a链接,第一个a连接,text(a链接的内容,例:>半壶纱<,半壶纱就是a链接的内容);即,最终的歌名; Elements urls = songTitles.get(i).getElementsByTag("a"); //System.out.println("@urls : " + urls); searchResult.setUrl(urls.get(0).attr("href"));//设置最终的url searchResult.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,显示结果 @Override protected 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; @Override public void onAttach(Context context) { super.onAttach(context); mainActivity = (MainActivity) getActivity(); //items = new String[]{"下载","取消"}; items = new String[]{getString(R.string.download),getString(R.string.cancel)}; } //创建对话框的事件方法 @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final AlertDialog.Builder builder = new AlertDialog.Builder(mainActivity); builder.setCancelable(true);//返回键可以取消 builder.setItems(items,new DialogInterface.OnClickListener(){ @Override public 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() { @Override public void onDowload(String mp3Url) { //下载成功 Toast.makeText(mainActivity, "下载成功", Toast.LENGTH_SHORT).show(); } @Override public 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(){ @Override public 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); } //获取下载音乐的URL private void getDownloadMusicURL(final SearchResult searchResult, final Handler handler) { mThreadPool.execute(new Runnable() { @Override public void run() { //http://music.xxxx.cn/#/album/1003215276 //1003215279 //http://music.xxxx.cn/order/1003215279/down/self/P2Z3Y12L1N2/3/001002A/1003215279 System.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++){ System.out.println("bb[" + i + "] = " + bb[i]); if (bb[i].indexOf("mp3?msisdn")>0){ System.out.println("mp3?msisdn = " + bb[i]); String initMp3Url = bb[i];//initMp3Url 初始Mp3下载链接,如下 //mp3?msisdn = ":"http://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 = "http://tyst.xxxx<span id="transmark"></span>.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() { @Override public void run() { try { Document doc = Jsoup.connect(url).userAgent(Constant.USER_AGENT).timeout(6000).get(); Elements lrcTag = doc.select("div.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(); } } }); } //下载MP3 private void downloadMusic(final SearchResult searchResult,final String url,final Handler handler){ mThreadPool.execute(new Runnable() { @Override public 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 用于返回数据 @Override public 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() { @Override public 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++){ SearchResult searchResult = new SearchResult(); //System.out.println("@searchResult : " + searchResult); //<a href="/song/121353608" //<a href="/song/264506450" //a链接,存在urls集合中;即,歌曲url集合; //a链接,第一个a连接,href属性的值;即,最终的url; //a链接,第一个a连接,text(a链接的内容,例:>半壶纱<,半壶纱就是a链接的内容);即,最终的歌名; Elements urls = songTitles.get(i).getElementsByTag("a"); //System.out.println("@urls : " + urls); searchResult.setUrl(urls.get(0).attr("href"));//设置最终的url searchResult.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); } }
Android开发本地及网络Mp3音乐播放器(十四)网络音乐下载功能实现
标签:
原文地址:http://blog.csdn.net/iwanghang/article/details/51340910