1、MediaPlayer状态

  • 在编写与 MediaPlayer相关的代码时,请始终牢记该状态图,因为从错误的状态调用其方法是导致错误发生的常见原因。

image.png

1-1、Idle(就绪)状态及End(结束)状态

  • Idle:创建MP实例或者调用reset函数,处于Idle状态;
  • 此外,使用new操作符创建的MediaPlayer对象处于Idle状态,而那些通过重载的create()便利方法创建的MediaPlayer对象却不是处于Idle状态。事实上,如果成功调用了重载的create()方法,那么这些对象已经是Prepare状态了。
  • End:调用release函数,就会变成End状态。当处于End状态时,它将不能再被使用,不能再回到其他状态。

    1-2、Error(错误)状态

  • 在构造一个新的MP实例或者调用reset函数,即在处于Idle状态时,调用getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(), setAudioStreamType(int), setLooping(boolean),setVolume(float, float), pause(), start(), stop(), seekTo(int), prepare() 或者 prepareAsync() 方法都是编程错误。

    1-3、Initialized(初始化)状态

  • 当调用setDataSourse()函数时,MP将会从Idle状态变为Initialized状态;

  • 如果在非Idle状态调用setDataSourse,会抛出IllegalStateExecption异常。
  • 当重载setDataSourse时需要抛出IllegalArgumentException(非法参数异常)和IOException两个异常。

    1-4、Prepared(准备)状态

  • 有两种途径到达Prepared状态

  • (1)同步方式(使用本地音视频文件):调用parpare(同步函数)将从Initialized状态变为Prepared状态。
  • (2)异步方式(使用网络数据,需要缓冲数据):调用prepareAsync(异步函数)将从Initialized状态变为Preparing状态,最后到Prepared。

    1-5、Started(开始)状态

  • 进入Prepared状态后,上层应用可以设置一些属性(音量等),必须调用start函数并成功返回,MP的状态由Prepared变为Started。

  • 如果MediaPlayer已处于Started状态,再调用start函数无效。

    1-6、Pause(暂停)状态

  • MP在播放控制时可以是Pause状态和Stop状态,且当前播放进度可以被调整。

  • 调用MediaPlayer.pause函数,有Started变为Pause,这个过程是瞬时的。

    1-7、Stopped(停止)状态

  • 调用stop函数时,无论处于Started、Paused、Prepared或PlaybackCompleted哪种状态,都会进入Stopped状态。

  • 一旦处于Stopped状态,playback将不能开始,直到MP重新处于Prepared状态。

    1-8、PlaybackCompleted(播放完成)状态

  • 当前播放位置可通过getCurrentPosition函数获取。

  • MP播放到数据流末尾,一次播放过程完成,如果事先调用setLooping(true),表示循环播放,MP依然处于Started状态。
  • 如果不循环播放,一次播放完成后MP进入PlaybackCompleted,此时调用start函数,将重启播放器从头开始播放数据。

    2、常见错误

    2-1、Error (-38,0)

  • 代码例子1

    1. mediaPlayer = new MediaPlayer();
    2. mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    3. @Override
    4. public void onPrepared(MediaPlayer mp) {
    5. Log.d(TAG, "onPrepared: " + mp.toString());
    6. }
    7. });
    8. mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
    9. @Override
    10. public void onCompletion(MediaPlayer mp) {
    11. Log.d(TAG, "onCompletion: " + mp.toString());
    12. }
    13. });
    14. mediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
    15. @Override
    16. public void onSeekComplete(MediaPlayer mp) {
    17. Log.d(TAG, "onSeekComplete: " + mp.toString());
    18. }
    19. });
    20. mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
    21. @Override
    22. public boolean onError(MediaPlayer mp, int what, int extra) {
    23. Log.e(TAG, "onError: what = " + what + ", extra = " + extra);
    24. return false;
    25. }
    26. });
    27. try {
    28. String url = "http://hipanda.hf.openstorage.cn/talkres/LTP_Poem_Res/3f6ad10fe8e0434d99acaa6c9e4ee935.mp3";
    29. // 没有setDataSourceprepare,此时处于IDLE状态
    30. mediaPlayer.start();
    31. } catch (Exception e) {
    32. Log.e(TAG, "start: " + e.toString());
    33. e.printStackTrace();
    34. }
  • 错误日志

  • start called in state 1:表示状态不对,当前状态是1 IDLE

    1. MediaPlayer: start called in state 1, mPlayer(0x0)
    2. MediaPlayer: error (-38, 0)
    3. MediaPlayer: Error (-38,0)
    4. MainActivity: onError: what = -38, extra = 0
    5. MainActivity: onCompletion: android.media.MediaPlayer@3dbc775
  • 代码例子2

    1. mediaPlayer = new MediaPlayer();
    2. mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    3. @Override
    4. public void onPrepared(MediaPlayer mp) {
    5. Log.d(TAG, "onPrepared: " + mp.toString());
    6. }
    7. });
    8. mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
    9. @Override
    10. public void onCompletion(MediaPlayer mp) {
    11. Log.d(TAG, "onCompletion: " + mp.toString());
    12. }
    13. });
    14. mediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
    15. @Override
    16. public void onSeekComplete(MediaPlayer mp) {
    17. Log.d(TAG, "onSeekComplete: " + mp.toString());
    18. }
    19. });
    20. mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
    21. @Override
    22. public boolean onError(MediaPlayer mp, int what, int extra) {
    23. Log.e(TAG, "onError: what = " + what + ", extra = " + extra);
    24. return false;
    25. }
    26. });
    27. try {
    28. String url = "http://hipanda.hf.openstorage.cn/talkres/LTP_Poem_Res/3f6ad10fe8e0434d99acaa6c9e4ee935.mp3";
    29. mediaPlayer.setDataSource(url);
    30. // setDataSource, 但是没有prepare,此时处于INIT状态
    31. mediaPlayer.start();
    32. } catch (Exception e) {
    33. Log.e(TAG, "start: " + e.toString());
    34. e.printStackTrace();
    35. }
  • 错误日志

  • start called in state 2:表示状态不对,当前状态是2 INIT

    1. MediaPlayer: start called in state 2, mPlayer(0x8d97f060)
    2. MediaPlayer: error (-38, 0)
    3. MediaPlayer: Error (-38,0)
    4. MainActivity: onError: what = -38, extra = 0

    2-2、release之后调用pause方法

  • 错误日志

    1. Caused by: java.lang.IllegalStateException
    2. at android.media.MediaPlayer._pause(Native Method)
    3. at android.media.MediaPlayer.pause(MediaPlayer.java:1249)
    4. at com.xinhe.androidd.MainActivity.pause(MainActivity.java:69)
    5. at java.lang.reflect.Method.invoke(Native Method)
    6. at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:409)
    7. at android.view.View.performClick(View.java:5637)
    8. at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:992)
    9. at android.view.View$PerformClick.run(View.java:22429)
    10. at android.os.Handler.handleCallback(Handler.java:751)
    11. at android.os.Handler.dispatchMessage(Handler.java:95)
    12. at android.os.Looper.loop(Looper.java:154)
    13. at android.app.ActivityThread.main(ActivityThread.java:6119)
    14. at java.lang.reflect.Method.invoke(Native Method)
    15. at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
    16. at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

    MediaPlayerNative: stop called in state 1, mPlayer(0x0)
    MediaPlayerNative: error (-38, 0)