本地音乐播放器(四)——总结篇

在总结之前,先来考虑两个问题:
1. 如果我们在一个比较安静的环境中带着耳机正在听歌,不小心将耳机拔出,此时音乐还是继续播放的,这时候势必会影响周围人,自己也会很尴尬,所以,能不能再拔出耳机后暂停播放呢?
2. 如果手机上有多个音乐播放器时,当其他音乐播放器正在播放音乐时,我们突然打开自己的播放器播放音乐,此时两个播放器会同时播放,这势必影响我们听歌,所以,能不能在我们播放的时候自动停止另一个播放器播放呢?

接下来,我们就来解决这两个问题。
一. 一些额外问题的解决:
(1) 拔出耳机,暂停播放:
Android中,当耳机拔出时,系统会发送一个广播,只要我们的接收器接收这个广播,那么我们就可以对拔出耳机事件做处理

 //注册接收器
 mReceiver = new ServiceReceiver();
 IntentFilter filter = new IntentFilter();
 filter.addAction(Contants.SERVER_RECEIVER_ACTION);
 filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
 registerReceiver(mReceiver, filter);

这是服务中接收器的注册,注意:我们的filter中多增加了一个action——AudioManager.ACTION_AUDIO_BECOMING_NOISY,这个就是接收拔出耳机广播的action。既然接收这个广播,我们就需要在onReceive中做相应的处理:

//监听耳机拔出动作,耳机拔出后需暂停音乐
  case AudioManager.ACTION_AUDIO_BECOMING_NOISY:
     if (isPlaying()) {
         mMediaPlayer.pause();
         mMusicState = Contants.PAUSE;
         sendBroadcastToActivity();
     }
     break;

当耳机拔出时,如果音乐还正在播放,则暂停音乐,并发送广播更新界面。如此,就实现了拔出耳机暂停播放的功能,貌似也挺简单的嘛。

(2) 实现手机中单音乐播放器播放:
首先来介绍一个概念——音频焦点:
Android 2.2开始,Android平台为应用程序提供了一个方式来协商设备的音频输出,这个机制被称为音频焦点。
当您的应用程序需要输出音频,如音乐或一个通知,这时你就必须请求音频焦点。一旦得到焦点,它就可以自由的使用声音输出设备,同时它会不断监听焦点的更改。如果它被通知已经失去了音频焦点,它会要么立即杀死音频或立即降低到一个安静的水平(被称为“ducking”——有一个标记,指示哪一个是适当的)当它再次接收焦点时,继续不断播放。
首先获取音频管理器和初始化音频焦点监听器:

mAmanager = (AudioManager) getApplicationContext().
                getSystemService(Context.AUDIO_SERVICE); 
mListener = new MyOnAudioFocusChangeListener();

在监听器中,对失去焦点做处理:

    /**
     * 音频焦点的监听器
     */
    class MyOnAudioFocusChangeListener implements
            AudioManager.OnAudioFocusChangeListener
    {
        @Override
        public void onAudioFocusChange(int focusChange)
        {
            switch (focusChange){
                //长时间失去焦点
                case AudioManager.AUDIOFOCUS_LOSS:
                    if (isPlaying()){
                        mMusicState = Contants.PAUSE;
                        mMediaPlayer.pause();
                        sendBroadcastToActivity();
                    }
                    break;
                //短时间失去焦点
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:

                    break;
                //获得焦点
                case AudioManager.AUDIOFOCUS_GAIN:

                    break;
            }

        }
    }

当长时间失去焦点时,暂停音乐。
获取音频焦点:

 int result = mAmanager.requestAudioFocus(mListener,
                AudioManager.STREAM_MUSIC,
                AudioManager.AUDIOFOCUS_GAIN);
 if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED){
     //执行播放操作
 }

只有当result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED时,才可以播放音乐。之前我们分析,控制音乐播放的入口有四个,分别是在列表选择播放歌曲,点击播放按钮,点击上一首按钮,点击下一首按钮,其中选择播放,上一首,下一首都会调用replay方法,而点击播放按钮会调用updateMusicState方法,所有我们只要在这两个方法中获取音频焦点即可,然后根据结果做相应处理。到此,第二个问题也解决了。

(3) 主界面的旋转动画:
在主界面有一个圆形的图片区域,这里放置的时候每个音乐相关的图片,但由于我们是本地音乐,所以我直接放置了一个默认图片,此图片有一个动画,就是在播放音乐时,旋转图片,暂停音乐时,则暂停旋转,怎么实现的呢?

 /**
     * 初始化动画
     */
    private void initAnimation(){
        mAnimator = ObjectAnimator.ofFloat(mMusicImage, "rotation", 0, 360);
        mAnimator.setDuration(6000);
        mAnimator.setInterpolator(new LinearInterpolator());
        mAnimator.setRepeatCount(-1);   //无限重复播放
        mAnimator.setRepeatMode(ObjectAnimator.INFINITE);
    }

可以看到,这里使用是属性动画,因为属性动画比补间动画更强大,他可以随时暂停和播放,而且用起来也是相当简单。先初始化动画为旋转动画,然后设置时长为6秒,并且匀速运动,无线重复播放。我们还需要将动画的播放暂停与音乐同步:

 /**
     * 更新当前音乐的相关信息
     */
    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void updateMusicInfo(int musicMode, int musicPlayPos) {
        mTvMusicName.setText(mPlayingMusic.getName());
        mTotalTime.setText(Utils.formatToString(mPlayingMusic.getTotalTime()));
        if (mMusicState == Contants.PLAY) {
            mMusicPlay.setImageResource(R.mipmap.img_music_pause);
            if (!mAnimator.isStarted()){    //启动动画
                mAnimator.start();
            }
            if (mAnimator.isPaused()){  //如果动画暂停,播放动画
                mAnimator.resume();
            }
        } else {
            mMusicPlay.setImageResource(R.mipmap.img_music_play);
            if (mAnimator.isRunning()){ //如果动画播放,暂停动画
                mAnimator.pause();
            }
        }
        updateMusicMode(musicMode);
        updateMusicSeekBar(musicPlayPos);
    }

在updateMusicInfo方法中可以看到,当音乐暂停时,我们暂停了动画,当音乐播放时,播放动画。

二. 总结:
总体分析这个项目,其实功能点并不是很多,我只是实现了音乐播放器的一下基本功能,和比较成熟的播放器比,还差很多,比如播放歌词,在线播放歌曲等等都没有。当然,我只是练练手,不可能最这么全,说一说体会吧。
在写这几篇博客时,基本上思路都是比较清晰的,因为我已经做完了所有的功能,也都理清了思路,所以还是比较快的,但是在刚开始要做的时候,真的是两眼一黑,就知道音乐需要后台播放,其他什么也不懂,就开始编码,在做的过程中,发现了许许多多的问题,导致我重构了三次代码,才基本得到了我想要的效果,这样,确实浪费了很多时间。在一开始的时候,并没有比较深入的去剖析音乐播放器的需求,且去了解哪些逻辑实现需要放在服务里,哪些需要放在界面上?过程中也没有记录解决一些问题的思路,导致做完后也并没有一个很完整的概念,总感觉零零散散的,所以,才写了这几篇博客来重新梳理和整理一下思路,看来在做项目中还有很多东西需要慢慢学习和体会。

终于写完了,带着感冒写到现在,哎,对自己也是醉了,不说了,最后附上源码~~

源码下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值