用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


本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏芋道源码1024

面试问烂的 Spring MVC 过程

来源:https://www.jianshu.com/p/e18fd44964eb

1933
来自专栏非著名程序员

Android WebView 上传文件支持全解析

声明:原文地址:http://blog.isming.me/2015/12/21/android-webview-upload-file/,转载请注明出处。 默...

1.3K7
来自专栏向治洪

React Native调用Android相机图库

概述 在很多的React Native开发中,我们需要调用原生的api实现调用相机和图库的功能,网上用的最多的开源库如:react-native-image-p...

2495
来自专栏向治洪

React Native调用Android相机图库

概述 在很多的React Native开发中,我们需要调用原生的api实现调用相机和图库的功能,网上用的最多的开源库如:react-native-image-p...

3079
来自专栏开发之途

Gradle 常用配置总结

当项目逐渐演进的过程中,主工程依赖的 Module 可能会越来越多,此时就需要统一配置各个 Module 的编译参数了

1913
来自专栏向治洪

将图库的图片剪切并保存

最近有些用户反映保存图片之后在系统图库找不到保存的图片,遂决定彻底查看并解决下。 Adnroid中保存图片的方法可能有如下两种: 第一种是自己写方法,如下代...

24810
来自专栏向治洪

Android 应用安装过程分析

在之前的文章中,我们对PakageManagerService启动流程分析 做了简单的介绍,并对PMS系统的启动流程做了详细的解析。上面只是说到了Android...

7579
来自专栏小巫技术博客

Retrofit2 & RxJava2实现单文件和多文件上传

6054
来自专栏Android源码框架分析

Android Bitmap变迁与原理解析(4.x-8.x)

App开发不可避免的要和图片打交道,由于其占用内存非常大,管理不当很容易导致内存不足,最后OOM,图片的背后其实是Bitmap,它是Android中最能吃内存的...

6804
来自专栏计算机编程

Android 自定义 svg 颜色

源码注释告诉了我们:此获取的drawable不与其他drawable 共享,简而言之,就是构建单独的内存模块来存储此drawable达到相互不影响的状态。

2383

扫码关注云+社区

领取腾讯云代金券