Android音乐播放器4.0(播放详情页中)

249 阅读3分钟

这是我参与2022首次更文挑战的第22天,活动详情查看:2022首次更文挑战

效果图

在这里插入图片描述

更新进度条

要更新进度条,需要 PlayMusicService 中发送广播,每秒发送广播,广播中携带播放进度信息,因此在 PlayMusicService 的 onCreate 方法中开启一个线程,写在 onCreate 中保证只起一条线程

private boolean isLoop = true;

    /**
     * 当service实例创建时执行
     */
    @Override
    public void onCreate() {
        super.onCreate();
        //给mediaPlayer加监听
        ......
        //启动工作线程,每隔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);
                }
            }
        }
    }

Activity 中修改广播接收器的代码

    private SeekBar seekBar;
    private TextView tv_play_music_total_time;
    private TextView tv_play_music_current_time;
    
	private void setViews() {
       	......
        seekBar = findViewById(R.id.sk_play_music_progress);
        tv_play_music_total_time = findViewById(R.id.tv_play_music_total_time);
        tv_play_music_current_time = findViewById(R.id.tv_play_music_current_time);
    }
	/**
     * 注册广播接收器
     */
    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 PlayMusicService.MusicBinder 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 中增加播放或暂停的方法

首先给 MusicBinder 中的 MusicBinder 中增加播放或暂停的方法

        //暂停或开始播放
        public void playOrPause(){
            if(mediaPlayer.isPlaying()){
                mediaPlayer.pause();
            }else {
                mediaPlayer.start();
            }
        }

Activity 给三个图片(上一首,下一首,暂停图片)增加点击事件

public class TestActivity extends AppCompatActivity implements View.OnClickListener {
    ......
    private MusicApplication app;

    private ImageView img_pre_music;
    private ImageView img_pause_music;
    private ImageView img_next_music;
    private MusicModel musicModel = new MusicModel();

	......

    private void setViews() {
		......
        img_pre_music = findViewById(R.id.img_pre_music);
        img_pause_music = findViewById(R.id.img_pause_music);
        img_next_music = findViewById(R.id.img_next_music);
    }
	......
    private void setListeners() {
        ......
        imgMusicThumb.setOnClickListener(this);
        img_pre_music.setOnClickListener(this);
        img_pause_music.setOnClickListener(this);
        img_next_music.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            ......
            case R.id.img_pre_music:
                app.setPosition(app.getPosition() == 0 ? 0 : app.getPosition() - 1);
                //这里会出空指针,当前歌曲只有在点击播放后才能拿到currentmusic的信息
                final MusicItem music = app.getCurrentMusic();
                if (music.url != null) {//基本信息已经加载过
                    //播放音乐
                    binder.playMusic(music.url);
                } else {
                    //通过songid获取基本信息
                    musicModel.loadMusicInfoBySongId(music.id, new MusicInfoCallback() {
                        @Override
                        public void onMusicInfoLoaded(MusicItem musicItem) {
                            music.url = musicItem.url;
                            music.id = musicItem.id;
                            binder.playMusic(musicItem.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 MusicItem music2 = app.getCurrentMusic();
                if (music2.url != null) {//基本信息已经加载过
                    //播放音乐
                    binder.playMusic(music2.url);
                } else {
                    //通过songid获取基本信息
                    musicModel.loadMusicInfoBySongId(music2.id, new MusicInfoCallback() {
                        @Override
                        public void onMusicInfoLoaded(MusicItem musicItem) {
                            music2.url = musicItem.url;
                            music2.id = musicItem.id;
                            binder.playMusic(musicItem.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;
            }
        });
        ......
}

显示标题和专辑

这一步很简单,在 Activity 中,广播接收器接收到开始的通知时,显示标题和专辑即可

/**
     * 接收音乐信息的广播接收器
     */
    class MusicInfoBroadCastReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(Globalconsts.ACTION_UPDATE_MUSIC_PROGRESS)) {
                ......
            } else if (action.equals(Globalconsts.ACTION_MUSIC_STARTED)) {
                //开始播放音乐,获取当前音乐对象
                app = MusicApplication.getApp();
                MusicItem music = app.getCurrentMusic();
                String pic = music.albumPic;
                final String title = music.name;
                tv_play_music_title.setText(title);
                tv_play_music_singer.setText(music.albumName);
                ......
            }
        }
    }