如何写一个正经的Android音乐播放器 三

实现音乐的播放。

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);
    }



猜你喜欢

转载自blog.csdn.net/boybeak/article/details/41930813