本地音乐播放器——总结篇
Posted xingxing_yan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了本地音乐播放器——总结篇相关的知识,希望对你有一定的参考价值。
在总结之前,先来考虑两个问题:
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方法中可以看到,当音乐暂停时,我们暂停了动画,当音乐播放时,播放动画。
二. 总结:
总体分析这个项目,其实功能点并不是很多,我只是实现了音乐播放器的一下基本功能,和比较成熟的播放器比,还差很多,比如播放歌词,在线播放歌曲等等都没有。当然,我只是练练手,不可能最这么全,说一说体会吧。
在写这几篇博客时,基本上思路都是比较清晰的,因为我已经做完了所有的功能,也都理清了思路,所以还是比较快的,但是在刚开始要做的时候,真的是两眼一黑,就知道音乐需要后台播放,其他什么也不懂,就开始编码,在做的过程中,发现了许许多多的问题,导致我重构了三次代码,才基本得到了我想要的效果,这样,确实浪费了很多时间。在一开始的时候,并没有比较深入的去剖析音乐播放器的需求,且去了解哪些逻辑实现需要放在服务里,哪些需要放在界面上?过程中也没有记录解决一些问题的思路,导致做完后也并没有一个很完整的概念,总感觉零零散散的,所以,才写了这几篇博客来重新梳理和整理一下思路,看来在做项目中还有很多东西需要慢慢学习和体会。
终于写完了,带着感冒写到现在,哎,对自己也是醉了,不说了,最后附上源码~~
以上是关于本地音乐播放器——总结篇的主要内容,如果未能解决你的问题,请参考以下文章