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

简介: 传送到github看源码下载apk试用 密码:rukn前言想在天朝听音乐还是有些难度的, 一般来说, 两三个app还是要的. 那何不尝试自己做个手机播放器, 听个爽呢?!今天就带大家先做个简单的带进度条可拖动的音乐播放器.

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


目录
相关文章
|
Android开发 Java API
Android中(Service )服务的最佳实践——后台执行的定时任务
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010046908/article/details/47727367             Android中的定时任务一般有两种实现方式,一种是使用Java API里提供的Timer类,一种是使用Android的Alarm机制。
5000 0
|
11月前
|
数据可视化 项目管理
个人和团队都好用的年度复盘工具:看板与KPT方法解析
本文带你了解高效方法KPT复盘法(Keep、Problem、Try),结合看板工具,帮助你理清头绪,快速完成年度复盘。
903 7
个人和团队都好用的年度复盘工具:看板与KPT方法解析
|
人工智能 并行计算 算法
一键抠图,毛发毕现:这个GitHub项目助你快速PS
快速抠图不留痕,设计看了都精神。
2741 0
一键抠图,毛发毕现:这个GitHub项目助你快速PS
Qt6.5打包(QT windeployqt不是内部或外部命令、QT错误:缺少libgcc_s_seh-1.dll ,无法正常启动(0xc000007b) 问题解决方法)
Qt6.5打包(QT windeployqt不是内部或外部命令、QT错误:缺少libgcc_s_seh-1.dll ,无法正常启动(0xc000007b) 问题解决方法)
1614 1
|
消息中间件 Oracle 关系型数据库
实时计算 Flink版产品使用合集之如果想自定义connector和pipeline要如何入手
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStreamAPI、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
NoSQL Linux Redis
CentOS 7.6安装 Redis-6.2.5
CentOS 7.6安装 Redis-6.2.5
467 0
CentOS 7.6安装 Redis-6.2.5
|
自然语言处理 JavaScript 前端开发
|
Java 关系型数据库 MySQL
Flink1.18.1和CDC2.4.1 本地没问题 提交任务到服务器 报错java.lang.NoClassDefFoundError: Could not initialize class io.debezium.connector.mysql.MySqlConnectorConfig
【2月更文挑战第33天】Flink1.18.1和CDC2.4.1 本地没问题 提交任务到服务器 报错java.lang.NoClassDefFoundError: Could not initialize class io.debezium.connector.mysql.MySqlConnectorConfig
1589 2
|
人工智能 数据安全/隐私保护
如何实现AI检测与反检测原理
AI检测器用于识别AI生成的文本,如ChatGPT,通过困惑度和爆发性指标评估文本。低困惑度和低爆发性可能指示AI创作。OpenAI正研发AI文本水印系统,但尚处早期阶段。现有检测器对长文本较准确,但非100%可靠,最高准确率约84%。工具如AIUNDETECT和AI Humanizer提供AI检测解决方案,适用于学生、研究人员和内容创作者。
|
JavaScript 前端开发 搜索推荐
JavaScript 延迟加载的艺术:按需加载的最佳实践
JavaScript 延迟加载的艺术:按需加载的最佳实践
JavaScript 延迟加载的艺术:按需加载的最佳实践