美文网首页实用知识Android技术知识Android开发
用MediaPlayer做个带进度条可后台的音乐播放器

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

作者: sean_depp | 来源:发表于2018-01-04 16:22 被阅读1169次

    传送到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


    相关文章

      网友评论

      • 叮宕:本地好办,在线咋整
      • 曾几何时还有梦:这很难吗😅
        sean_depp:@曾几何时还有梦 不难呀,我这不是写着玩吗?
      • c557429bc747:就不能直接发软件嘛
        sean_depp:@吴蜀黍 嗯,我确实应该加个某度盘链接的apk的。
        sean_depp:@星石_未陨 那我会之后加个apk的包链接?
        吴蜀黍:这不是软件是再教你如何使用MediaPlayer来编程

      本文标题:用MediaPlayer做个带进度条可后台的音乐播放器

      本文链接:https://www.haomeiwen.com/subject/hhbrnxtx.html