編輯:關於Android編程
實現效果如圖:

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 searchResults = new ArrayList();
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 results) {
ArrayList 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{
//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半壺紗<,半壺紗就是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;i0){
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.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)msg.obj);
break;
case Constant.FAILED:
if (mListener != null) mListener.onSearchResult(null);
break;
}
}
};
//執行線程
mThreadPool.execute(new Runnable() {
@Override
public void run() {//run方法
ArrayList results = getMusicList(key,page);
if(results == null){
handler.sendEmptyMessage(Constant.FAILED);
return;
}
handler.obtainMessage(Constant.SUCCESS,results).sendToTarget();
}
});
}
//使用Jsoup組件請求網絡,並解析音樂數據
private ArrayList getMusicList(final String key,final int page){
final String start = String.valueOf((page - 1) * SIZE);
ArrayList searchResults = new ArrayList();
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半壺紗<,半壺紗就是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 results);
}
}
Android權限
系統權限 在運行時請求權限系統權限 Android是一個權限分離的操作系統,每個應用使用不同的系統身份運行(Linux用戶ID和群組ID)。系統的不同部分也被分隔進不同
僅5步搞定Android開發環境部署 Android開發環境搭建教程
在windows安裝Android的開發環境不簡單也說不上算復雜,本文寫給第一次想在自己Windows上建立Android開發環境投入Android浪潮的朋友們,為了確保
Android Studio使用Lint進行代碼檢查
Android Studio目前已經更新到1.4版本,它作為Google官方推薦的IDE,功能非常強大,其中提供了一套靜態代碼分析工具,它可以幫助我們檢查項目中存在的問題
GridView
public class DragGrid extends GridView { /** 點擊時候的X位置 */ public int downX; /