【達內課程】音樂播放器4.0(播放詳情頁下)
阿新 • • 發佈:2018-11-03
效果圖
要更新進度條,需要PlayMusicService中傳送廣播,每秒傳送廣播,廣播中攜帶播放進度資訊
因此在PlayMusicService的onCreate方法中開啟一個執行緒,寫在onCreate中保證只起一條執行緒
private boolean isLoop = true; /** * 當service例項建立時執行 */ @Override public void onCreate() { super.onCreate(); //給mediaPlayer加監聽 mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { //音樂已經準備好 @Override public void onPrepared(MediaPlayer mediaPlayer) { mediaPlayer.start(); //傳送廣播,通知activity音樂已經開始播放 Intent intent = new Intent (Globalconsts.ACTION_MUSIC_STARTED); sendBroadcast(intent); } }); //啟動工作執行緒,每隔1s傳送一次更新進度的廣播 new updateProgressThread().start(); } /** * 更新進度的執行緒 * 每秒傳送廣播,廣播中攜帶播放進度資訊 */ class updateProgressThread extends Thread{ @Override public void run() { while (isLoop){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //傳送自定義廣播 if(mediaPlayer.isPlaying()){ int total = mediaPlayer.getDuration(); int currentPosition = mediaPlayer.getCurrentPosition(); Intent intent = new Intent(Globalconsts.ACTION_UPDATE_MUSIC_PROGRESS); intent.putExtra("total",total); intent.putExtra("current",currentPosition); sendBroadcast(intent); } } } }
MainActivity中修改廣播接收器的程式碼
/** * 註冊廣播接收器 */ private void registMusicReceiver() { receiver = new MusicInfoBroadCastReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Globalconsts.ACTION_MUSIC_STARTED); intentFilter.addAction(Globalconsts.ACTION_UPDATE_MUSIC_PROGRESS); this.registerReceiver(receiver, intentFilter); } ...... /** * 接收音樂資訊的廣播接收器 */ class MusicInfoBroadCastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(Globalconsts.ACTION_UPDATE_MUSIC_PROGRESS)) { //獲取廣播中的total\current int total = intent.getIntExtra("total", 0); int current = intent.getIntExtra("current", 0); //更新seekbar seekBar.setMax(total); seekBar.setProgress(current); String totalStr = Globalconsts.FORMAT.format(new Date(total)); String currentStr = Globalconsts.FORMAT.format(new Date(current)); tv_play_music_total_time.setText(totalStr); tv_play_music_current_time.setText(currentStr); } else if (action.equals(Globalconsts.ACTION_MUSIC_STARTED)) { ...... } } }
同時,Globalconsts增加
public static final SimpleDateFormat FORMAT = new SimpleDateFormat("mm:ss");
//音樂開始播放 廣播action
public static final String ACTION_MUSIC_STARTED = "ACTION_MUSIC_STARTED";
給進度條增加拖拽事件,MainActivity中修改
bindMusicService()中的binder物件為全域性變數,同時
private void setListeners() { //給seekbar加監聽 seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) {//由使用者引起 //seekto binder.seekTo(progress); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); ...... }
PlayMusicService中MusicBinder 裡增加seekTo方法
public class MusicBinder extends Binder{
//定義供客戶端呼叫的方法
/**
* 跳轉到相應位置 繼續播放/暫停
*/
public void seekTo(int position){
mediaPlayer.seekTo(position);
}
......
}
實現上一曲和下一曲
給三個圖片(上一首,下一首,暫停圖片)增加點選事件,同時在
MusicBinder中MusicBinder中增加
//暫停或開始播放
public void playOrPause(){
if(mediaPlayer.isPlaying()){
mediaPlayer.pause();
}else {
mediaPlayer.start();
}
}
MainActivity中onClick
case R.id.img_pre_music:
app.setPosition(app.getPosition() == 0 ? 0 : app.getPosition() - 1);
//這裡會出空指標,當前歌曲只有在點選播放後才能拿到currentmusic的資訊
final Music music = app.getCurrentMusic();
if (music.getBitrate() != null) {//基本資訊已經載入過
//播放音樂
String url = music.getBitrate().getFile_link();
binder.playMusic(url);
} else {
//通過songid獲取基本資訊
musicModel.loadMusicInfoBySongId(music.getSong_id(), new MusicInfoCallback() {
@Override
public void onMusicInfoLoaded(Songinfo songinfo, BitrateModel bitrateModel) {
music.setBitrate(bitrateModel);
music.setSonginfo(songinfo);
String url = bitrateModel.getFile_link();
binder.playMusic(url);
}
});
}
break;
case R.id.img_pause_music:
binder.playOrPause();
break;
case R.id.img_next_music:
app.setPosition(app.getPosition() == app.getMusicList().size() - 1 ? 0 : app.getPosition() + 1);
final Music music2 = app.getCurrentMusic();
if (music2.getBitrate() != null) {//基本資訊已經載入過
//播放音樂
String url = music2.getBitrate().getFile_link();
binder.playMusic(url);
} else {
//通過songid獲取基本資訊
musicModel.loadMusicInfoBySongId(music2.getSong_id(), new MusicInfoCallback() {
@Override
public void onMusicInfoLoaded(Songinfo songinfo, BitrateModel bitrateModel) {
music2.setBitrate(bitrateModel);
music2.setSonginfo(songinfo);
String url = bitrateModel.getFile_link();
binder.playMusic(url);
}
});
}
break;
解決點選上一曲下一曲按鈕時,觸發listview的onclick事件,給rlPlayMusic加上onTouch事件,返回true即可
private void setListeners() {
//給rlPlayMusic註冊onTouch事件(觸控執行)
rlPlayMusic.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//如果返回true
return true;
//如果返回false
//return false;
}
});
......
}
歌詞顯示
根據song_id獲取歌曲資訊的介面中lrclink欄位是lrc歌詞,根據連結下載lrc歌詞
MusicModel中增加下載歌詞的方法
public void downloadLrc(final String lrclink, final LrcCallback callback) {
AsyncTask<String,String,HashMap<String,String>> task = new AsyncTask<String, String, HashMap<String, String>>() {
@Override
protected HashMap<String, String> doInBackground(String... strings) {
try {
InputStream is = HttpUtils.getInputStream(lrclink);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = "";
HashMap<String,String> lrc = new HashMap<>();
while ((line = reader.readLine())!=null){//讀到了歌詞的一行
if(line.length()<10){//一行中的資料不夠解析
continue;
}
//line:[00:07.00]音樂推廣營銷:奔跑怪物
//由於是顯示每秒的歌詞,所以擷取00:07
String key = line.substring(1,6);
String value;
if(line.length() == 10){//說明只有時間
value = "";
}else {
value = line.substring(10);
}
lrc.put(key,value);
}
return lrc;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(HashMap<String, String> hashMap) {
//返回上面的lrc
callback.onLrcLoaded(hashMap);
}
};
task.execute();
}
在Music這個model中增加
private HashMap<String,String> lrc;
public HashMap<String, String> getLrc() {
return lrc;
}
public void setLrc(HashMap<String, String> lrc) {
this.lrc = lrc;
}
MainActivity中
/**
* 接收音樂資訊的廣播接收器
*/
class MusicInfoBroadCastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Globalconsts.ACTION_UPDATE_MUSIC_PROGRESS)) {
......
MusicApplication app = MusicApplication.getApp();
Music music = app.getCurrentMusic();
HashMap<String,String> lrc = music.getLrc();
if(lrc!=null){//根據當前時間,獲取歌詞內容,更新textview
String lrcContent = lrc.get(currentStr);
if(lrcContent!=null){
img_play_music_lrc.setText(lrcContent);
}
}
} else if (action.equals(Globalconsts.ACTION_MUSIC_STARTED)) {
......
//更新頁面上其他
tv_play_music_title.setText(music.getSonginfo().getTitle());
tv_play_music_singer.setText(music.getSonginfo().getAuthor());
//下載歌詞
musicModel.downloadLrc(music.getSonginfo().getLrclink(), new LrcCallback() {
@Override
public void onLrcLoaded(HashMap<String, String> lrc) {
//將下載好的歌詞存入music物件
music.setLrc(lrc);
//把相對應的歌詞呈現在介面上
//每隔1s更新歌詞內容
//在更新音樂進度的廣播接收器中更新即可
}
});
}
}
}