1. 程式人生 > >【達內課程】音樂播放器4.0(播放詳情頁下)

【達內課程】音樂播放器4.0(播放詳情頁下)

效果圖

在這裡插入圖片描述
要更新進度條,需要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更新歌詞內容
                        //在更新音樂進度的廣播接收器中更新即可

                    }
                });
            }
        }
    }