用MediaPlayer做个带进度条可后台的音乐播放器

传送到github看源码
下载apk试用 密码:rukn


前言

  • 想在天朝听音乐还是有些难度的, 一般来说, 两三个app还是要的. 那何不尝试自己做个手机播放器, 听个爽呢?!今天就带大家先做个简单的带进度条可拖动的音乐播放器.
  • 添加了后台播放的功能, 很实用哦~

先看效果图

很尴尬的一点就是大家没法听到音乐, 就只能看看图片.

效果图

布局文件

布局文件

添加Service

我们需要先把Service添加进来, 再考虑使用MediaPlayer播放, 我们分步来说.

  • 首先要有一个自定义接口, 这个接口中的方法都是要在服务中实现的, 然后要到Activity中使用的.
public interface IService {
    //1. 定义接口IService, 添加调用函数, 调用MusicService中对应的函数
    public void callPlayMusic(String path);

    public void callPauseMusic();

    public void callConMusic();

    public void callSeekToPos(int pos);
}
  • 然后来看Service中的实现, 自定义一个类, 继承Binder, 然后实现我们再接口中定义的方法.
    /**
     * 类MyBinder继承Binder实现接口IService
     */
    private class MyBinder extends Binder implements IService {
        //2. 定义类MyBinder继承Binder实现接口IService中的函数
        @Override
        public void callPlayMusic(String path) {
            playMusic(path);
        }

        @Override
        public void callPauseMusic() {
            pauseMusic();
        }

        @Override
        public void callConMusic() {
            conMusic();
        }

        @Override
        public void callSeekToPos(int pos) {
            seekToPos(pos);
        }
    }
  • 具体的实现就要涉及到MediaPlayer的使用了, 我们等下说, 先把Service绑定到Activity. 首先要返回一个自定义类的实例.
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //3. 返回自定义类MyBinder对象
        return new MyBinder();
    }
  • 然后我们转到Activity来绑定服务
    //4. 开启服务
    Intent intent = new Intent(this, MusicService.class);
    startService(intent);

    //7. 绑定服务
    MyConn myConn = new MyConn();
    bindService(intent, myConn, BIND_AUTO_CREATE);
  • 中间的MyConn又是一个自定义的类, 我们来看下实现. 之中要获取下IService对象, 以此调用定义的函数.
    private class MyConn implements ServiceConnection {
        //5. 定义类MyConn实现接口ServiceConnection
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //6. 获取IBinder对象, 以此调用暴露的函数
            iService = (IService) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    }

MediaPlayer的使用

然后服务就完成一个绑定了, 之后我们来说下MediaPlayer和SeekBar的使用. 无非就是播放, 暂停, 继续这些的实现. 具体的说明请移步官方文档

    /**
     * 播放音乐
     *
     * @param path 播放文件的路径
     */
    public void playMusic(String path) {
        Log.i(TAG, "playMusic");
        try {
            mediaPlayer.reset();
            mediaPlayer.setDataSource(path);
            mediaPlayer.setLooping(true);
            mediaPlayer.prepare();
            mediaPlayer.start();

            updateSeekBar();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 暂停播放音乐
     */
    public void pauseMusic() {
        Log.i(TAG, "pauseMusic");
        if (mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
        }
    }

    /**
     * 继续播放音乐
     */
    public void conMusic() {
        Log.i(TAG, "conMusic");
        mediaPlayer.start();
    }

读取文件系统肯定是要权限的, 可以查看我之前的文章一个Util带你获取Android6.0以上的读写sdcard权限


进度条的设置

SeekBar这里用起来其实不难, 难就难在要从Service传数据到Activity. 这里我选用Handler, 当然你也可以用其它办法. 同样我们分步来说.

  • 之前调用mediaPlayer.start();之后我调用了一个updateSeekBar();, 现在来看看实现. 关键是要获取到音乐的总长度, 并且实时更新, 要实时更新的话, 我这里开了一个线程, 1s刷一次, 就不多说了.
    /**
     * 更新SeekBar
     */
    private void updateSeekBar() {
        //获取总时长
        final int duration = mediaPlayer.getDuration();

        //开启线程发送数据
        new Thread() {
            @Override
            public void run() {
                while (keepTrue) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    int currentPosition = mediaPlayer.getCurrentPosition();

                    //发送数据给activity
                    Message message = Message.obtain();
                    Bundle bundle = new Bundle();
                    bundle.putInt("duration", duration);
                    bundle.putInt("currentPosition", currentPosition);
                    message.setData(bundle);

                    MainActivity.handler.sendMessage(message);
                }
            }
        }.start();
    }
  • 然后回到Activity要接收发送的message. 接收到之后也完成的差不多了. 然后就是一个SeekBar的监听设置.
    public static Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Bundle data = msg.getData();
            int duration = data.getInt("duration");
            int currentPosition = data.getInt("currentPosition");

            sb_progress.setMax(duration);
            sb_progress.setProgress(currentPosition);
        }
    };
  • 就是在放开拖动SeekBar的时候重新设置位置, 要注意的是, 函数seekToPos也是在Service中实现的.
    //8. 设置进度条拖动事件
    sb_progress.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        }
    
        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
        }
    
        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            iService.callSeekToPos(seekBar.getProgress());
        }
    });
    /**
     * 设置SeekBar位置
     *
     * @param pos 当前位置
     */
    public void seekToPos(int pos) {
        mediaPlayer.seekTo(pos);
    }

这样就完成啦! 喜欢就赶紧下载试试吧! 有意见或者建议也可以评论区哦.


传送到github看源码
下载apk试用 密码:rukn


你可能感兴趣的:(用MediaPlayer做个带进度条可后台的音乐播放器)