1、MediaPlayer状态
- 在编写与 MediaPlayer相关的代码时,请始终牢记该状态图,因为从错误的状态调用其方法是导致错误发生的常见原因。
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
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
Log.d(TAG, "onPrepared: " + mp.toString());
}
});
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
Log.d(TAG, "onCompletion: " + mp.toString());
}
});
mediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
@Override
public void onSeekComplete(MediaPlayer mp) {
Log.d(TAG, "onSeekComplete: " + mp.toString());
}
});
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e(TAG, "onError: what = " + what + ", extra = " + extra);
return false;
}
});
try {
String url = "http://hipanda.hf.openstorage.cn/talkres/LTP_Poem_Res/3f6ad10fe8e0434d99acaa6c9e4ee935.mp3";
// 没有setDataSource、prepare,此时处于IDLE状态
mediaPlayer.start();
} catch (Exception e) {
Log.e(TAG, "start: " + e.toString());
e.printStackTrace();
}
错误日志
start called in state 1:表示状态不对,当前状态是1 IDLE
MediaPlayer: start called in state 1, mPlayer(0x0)
MediaPlayer: error (-38, 0)
MediaPlayer: Error (-38,0)
MainActivity: onError: what = -38, extra = 0
MainActivity: onCompletion: android.media.MediaPlayer@3dbc775
代码例子2
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
Log.d(TAG, "onPrepared: " + mp.toString());
}
});
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
Log.d(TAG, "onCompletion: " + mp.toString());
}
});
mediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
@Override
public void onSeekComplete(MediaPlayer mp) {
Log.d(TAG, "onSeekComplete: " + mp.toString());
}
});
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e(TAG, "onError: what = " + what + ", extra = " + extra);
return false;
}
});
try {
String url = "http://hipanda.hf.openstorage.cn/talkres/LTP_Poem_Res/3f6ad10fe8e0434d99acaa6c9e4ee935.mp3";
mediaPlayer.setDataSource(url);
// setDataSource, 但是没有prepare,此时处于INIT状态
mediaPlayer.start();
} catch (Exception e) {
Log.e(TAG, "start: " + e.toString());
e.printStackTrace();
}
错误日志
start called in state 2:表示状态不对,当前状态是2 INIT
MediaPlayer: start called in state 2, mPlayer(0x8d97f060)
MediaPlayer: error (-38, 0)
MediaPlayer: Error (-38,0)
MainActivity: onError: what = -38, extra = 0
2-2、release之后调用pause方法
错误日志
Caused by: java.lang.IllegalStateException
at android.media.MediaPlayer._pause(Native Method)
at android.media.MediaPlayer.pause(MediaPlayer.java:1249)
at com.xinhe.androidd.MainActivity.pause(MainActivity.java:69)
at java.lang.reflect.Method.invoke(Native Method)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:409)
at android.view.View.performClick(View.java:5637)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:992)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
MediaPlayerNative: stop called in state 1, mPlayer(0x0)
MediaPlayerNative: error (-38, 0)