实现音乐的播放。
为了快速实现音乐播放,我们使用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中,可以这样写开始播放的代码:
//这个方法用来初始化我们的MediaPlayerprivate 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); }