实现音乐的播放。 Github地址:https://github.com/boybeak/BeMusic
为了快速实现音乐播放,我们使用MediaPlayer而不用SoundPool,据说SoundPool比MediaPlayer的自由度更大。不过,根据我的了解,soundpool并不支持音频的解码,得自己去解码,而MeidaPlayer已经内置了一些解码方案,我看到的是,音频除了ape无损格式,都能播放。
你需要阅读:
MediaPlayer API:
http://developer.android.com/reference/android/media/MediaPlayer.html
MediaPlayer API Guide:
http://developer.android.com/guide/topics/media/mediaplayer.html
在此,不再介绍MediaPlayer的使用。
在途中,我们可以看到MediaPlayer的生命周期,其中,蓝色椭圆内的是Mediaplayer的不同状态。
如果在不允许的状态执行了一些不应该的操作,会出现异常。在进行不同操作时候,合法的前提状态和不合法的状态,参考这个链接:
http://developer.android.com/reference/android/media/MediaPlayer.html#Valid_and_Invalid_States
我们声明一个类来记录状态。
public static class State {
public static final int
IDLE = 0,
INITIALIZED = 1,
PREPARED = 2,
PREPARING = 3,
STARTED = 4,
PAUSED = 5,
STOPPED = 6,
COMPLETED = 7,
END = -1,
ERROR = -2;
}
在我们的MainService中,可以这样写开始播放的代码:
//这个方法用来初始化我们的MediaPlayer
private void init () {
if (mPlayer == null) {
mPlayer = new MediaPlayer();
changeState(State.IDLE);
} else {
if (mCurrentState == State.IDLE || mCurrentState == State.INITIALIZED || mCurrentState == State.PREPARED ||
mCurrentState == State.STARTED || mCurrentState == State.PAUSED || mCurrentState == State.STOPPED ||
mCurrentState == State.COMPLETED || mCurrentState == State.ERROR) {
mPlayer.reset();
changeState(State.IDLE); //注意状态更改的代码
}
}
mPlayer.setOnErrorListener(this); //MainService 要实现这三个接口
mPlayer.setOnPreparedListener(this);
mPlayer.setOnCompletionListener(this);
}
对外公开的一个开始播放的方法:
public void start (Audio audio) {
init();
try {
if (mCurrentState == State.IDLE) {
mPlayer.setDataSource(this, audio.getUri()); //Valid Sates IDLE
}
changeState(State.INITIALIZED);
if (mCurrentState != State.ERROR) {
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); //Invalid States ERROR
}
if (mCurrentState == State.INITIALIZED || mCurrentState == State.STOPPED) {
mPlayer.prepareAsync();//Valid Sates{Initialized, Stopped}
changeState(State.PREPARING);
}
} catch (IOException e) {
e.printStackTrace();
}
}
注意,在此方法中,我们不要直接去播放,而是使用mPlayer.prepareAsync()。让MediaPlayer去做申请播放资源等工作,这个过程有可能有几十毫秒的耗时,等到回调onPrepared回调成功后,在onPrepared中去做真正的开始播放,我们在onPrepared中调用一下doStart方法:
private void doStart () {
mPlayer.start();
changeState(State.STARTED);
}
这样,就可以开始播放工作了。在以上代码中,都出现了一个changeState方法。如下:
private void changeState (int state) {
mCurrentState = state;
if (mPlaybackListener != null) {
mPlaybackListener.onStateChanged(mCurrentAudio, mCurrentState);
}
}
/*这里采用了setOnPlaybackListener的方法,如果有需要,也可以用一个List去保存一个Listener集合,只要在适当的时候进行释放,例如在Service的onDestroy方法中,去把这个List清空掉*/
public void setOnPlaybackListener (OnPlaybackListener listener) {
mPlaybackListener = listener;
}
public static interface OnPlaybackListener {
public void onStateChanged (Audio source, int state);
}