前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用MediaPlayer做个带进度条可后台的音乐播放器

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

作者头像
sean_yang
发布2018-09-04 11:08:22
1.7K0
发布2018-09-04 11:08:22
举报
文章被收录于专栏:Sorrower的专栏Sorrower的专栏

传送到github看源码

下载apk试用 密码:rukn


前言

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

先看效果图

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

效果图


布局文件

布局文件


添加Service

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

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

    public void callPauseMusic();

    public void callConMusic();

    public void callSeekToPos(int pos);
}

  • 然后来看Service中的实现, 自定义一个类, 继承Binder, 然后实现我们再接口中定义的方法.
代码语言:javascript
复制
    /**
     * 类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. 首先要返回一个自定义类的实例.
代码语言:javascript
复制
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //3. 返回自定义类MyBinder对象
        return new MyBinder();
    }

  • 然后我们转到Activity来绑定服务
代码语言:javascript
复制
    //4. 开启服务
    Intent intent = new Intent(this, MusicService.class);
    startService(intent);

    //7. 绑定服务
    MyConn myConn = new MyConn();
    bindService(intent, myConn, BIND_AUTO_CREATE);

  • 中间的MyConn又是一个自定义的类, 我们来看下实现. 之中要获取下IService对象, 以此调用定义的函数.
代码语言:javascript
复制
    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的使用. 无非就是播放, 暂停, 继续这些的实现. 具体的说明请移步官方文档

代码语言:javascript
复制
    /**
     * 播放音乐
     *
     * @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刷一次, 就不多说了.
代码语言:javascript
复制
    /**
     * 更新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的监听设置.
代码语言:javascript
复制
    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中实现的.
代码语言:javascript
复制
    //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());
        }
    });
代码语言:javascript
复制
    /**
     * 设置SeekBar位置
     *
     * @param pos 当前位置
     */
    public void seekToPos(int pos) {
        mediaPlayer.seekTo(pos);
    }

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


传送到github看源码

下载apk试用 密码:rukn


本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.01.04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 先看效果图
  • 布局文件
  • 添加Service
  • MediaPlayer的使用
  • 进度条的设置
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档