Android MediaPlayer:应用 closes/press 后退按钮时出现 IllegalStateException
Android MediaPlayer : IllegalStateException when app closes/press back button
我正在使用媒体播放器从 url 流式传输 mp3 音频,现在我可以播放音乐,但是当 我按下后退按钮或关闭应用程序时,它会崩溃。
谁能帮我找出我的错误。
谢谢。
我的代码是:
private ImageView play, forward, backward;
private MediaPlayer mediaPlayer;
private boolean playing = false;
private ProgressDialog dialog;
private String mp3link;
private SeekBar seekbar;
private Handler handler = new Handler();
private int mediaPos;
private int mediaMax;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String url ="";
initWidgets();
}
private void initWidgets() {
mp3link = "http://loc8app.com/church/uploads/audio/749928ad6fcb7b1aceefdf03bd7a9465.mp3";
play = (ImageView) findViewById(R.id.control);
seekbar = (SeekBar) findViewById(R.id.seekBar);
// forward = (ImageView) findViewById(R.id.playeer_forward);
// backward = (ImageView) findViewById(R.id.playeer_back);
mediaPlayer = new MediaPlayer();
play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
playFunction();
}
});
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(mediaPlayer != null && fromUser){
mediaPlayer.seekTo(progress);
}
}
});
}
private void playFunction() {
if (!playing) {
try {
dialog = ProgressDialog
.show(MainActivity.this,
"",
getString(com.root5solutions.music.R.string.buffering),
true);
dialog.setCancelable(true);
dialog.show();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(mp3link);
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
play.setBackgroundResource(R.drawable.pause);
playing = true;
//this is new
mediaPos = mp.getCurrentPosition();
mediaMax = mp.getDuration();
seekbar.setMax(mediaMax);
seekbar.setProgress(mediaPos);
//this line is the error
handler.removeCallbacks(moveSeekBarThread);
handler.postDelayed(moveSeekBarThread, 100);
mp.start();
dialog.dismiss();
}
});
mediaPlayer.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
dialog.dismiss();
}
} else {
play.setBackgroundResource(R.drawable.play);
mediaPlayer.stop();
mediaPlayer.release();
playing = false;
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
private Runnable moveSeekBarThread = new Runnable() {
public void run() {
if (mediaPlayer.isPlaying()) {
int mediaPos_new = mediaPlayer.getCurrentPosition();
int mediaMax_new = mediaPlayer.getDuration();
seekbar.setMax(mediaMax_new);
seekbar.setProgress(mediaPos_new);
handler.postDelayed(this, 1000); // Looping the thread after 1 second
}
}
};
}
Logcat 显示:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.root.music, PID: 26981
java.lang.IllegalStateException
at android.media.MediaPlayer.isPlaying(Native Method)
at com.root.music.MainActivity.run(MainActivity.java:132)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5351)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:947)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:742)
你得到 IllegalStateException .
Signals that a method has been invoked at an illegal or inappropriate
time .
在 if 条件
之后调用 super.onBackPressed();
@Override
public void onBackPressed()
{
if (mediaPlayer!= null)
{
if(mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.release();
}
super.onBackPressed(); // Call here
}
问题似乎是由 moveSeekBarThread
Runnable
引起的,从中引发异常,在 onBackPressed()
释放 mediaPlayer
后继续执行.这导致 isPlaying()
方法被执行,根据 documentation 将导致 IllegalStateException
:
if the internal player engine has not been initialized or has been released.
查看 moveSeekBarThread
,它似乎被配置为通过延迟将自己发送回 handler
Handler
实例来无休止地重新安排自己。当用户离开 activity 时,此过程不会停止,这解释了为什么 moveSeekBarThread
保留 运行。因此,基于以上所述,一种解决方案可能是确保在用户离开 activity 时调用 mediaPlayer.release()
之前删除 handler
队列中的任何 moveSeekBarThread
实例].
您应该可以通过在调用 mediaPlayer.release()
之前调用 handler.removeCallbacks(moveSeekBarThread);
来实现。例如如下:
@Override
public void onBackPressed() {
super.onBackPressed();
handler.removeCallbacks(moveSeekBarThread);
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
在mediaPlayer.release()
之前调用应该没问题,但我觉得不管mediaPlayer
是否在播放都调用它比较安全。这样,如果 Runnable
确实以某种方式启动或保持启动状态,尽管媒体播放器尚未启动或已停止,Runnable
仍将被清除。
顺便说一句,虽然我没有任何使用 MediaPlayer
的经验,但我偶然注意到 release
方法的文档有以下内容:
It is considered good practice to call this method when you're done using the MediaPlayer. In particular, whenever an Activity of an application is paused (its onPause() method is called), or stopped (its onStop() method is called), this method should be invoked to release the MediaPlayer object, unless the application has a special need to keep the object around. In addition to unnecessary resources (such as memory and instances of codecs) being held, failure to call this method immediately if a MediaPlayer object is no longer needed may also lead to continuous battery consumption for mobile devices, and playback failure for other applications if no multiple instances of the same codec are supported on a device.
因此,除非在您的情况下有特殊需要将媒体播放器保留在 activity 中,否则最好处理发布过程(包括从 [=18 中清除 moveSeekBarThread
=]) 在 onPause
或 onStop
中。
希望对您有所帮助!
首先你需要明白illegalStateException是什么意思:
根据 Android 文档:
It Signals that a method has been invoked at an illegal or inappropriate time. In other words, the Java environment or Java application is not in an appropriate state for the requested operation.
看看媒体播放器的状态图:
https://developer.android.com/images/mediaplayer_state_diagram.gif
调用setDataSource(FileDescriptor),或setDataSource(String),或setDataSource(Context, Uri),或setDataSource(FileDescriptor, long, long),或setDataSource(MediaDataSource)将Idle状态的MediaPlayer对象传输到初始化状态。
如果在任何其他状态下调用 setDataSource(),则会抛出 IllegalStateException。
始终注意可能从重载的 setDataSource 方法中抛出的 IllegalArgumentException 和 IOException 是一种很好的编程习惯。
我正在使用媒体播放器从 url 流式传输 mp3 音频,现在我可以播放音乐,但是当 我按下后退按钮或关闭应用程序时,它会崩溃。 谁能帮我找出我的错误。 谢谢。
我的代码是:
private ImageView play, forward, backward;
private MediaPlayer mediaPlayer;
private boolean playing = false;
private ProgressDialog dialog;
private String mp3link;
private SeekBar seekbar;
private Handler handler = new Handler();
private int mediaPos;
private int mediaMax;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String url ="";
initWidgets();
}
private void initWidgets() {
mp3link = "http://loc8app.com/church/uploads/audio/749928ad6fcb7b1aceefdf03bd7a9465.mp3";
play = (ImageView) findViewById(R.id.control);
seekbar = (SeekBar) findViewById(R.id.seekBar);
// forward = (ImageView) findViewById(R.id.playeer_forward);
// backward = (ImageView) findViewById(R.id.playeer_back);
mediaPlayer = new MediaPlayer();
play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
playFunction();
}
});
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(mediaPlayer != null && fromUser){
mediaPlayer.seekTo(progress);
}
}
});
}
private void playFunction() {
if (!playing) {
try {
dialog = ProgressDialog
.show(MainActivity.this,
"",
getString(com.root5solutions.music.R.string.buffering),
true);
dialog.setCancelable(true);
dialog.show();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(mp3link);
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
play.setBackgroundResource(R.drawable.pause);
playing = true;
//this is new
mediaPos = mp.getCurrentPosition();
mediaMax = mp.getDuration();
seekbar.setMax(mediaMax);
seekbar.setProgress(mediaPos);
//this line is the error
handler.removeCallbacks(moveSeekBarThread);
handler.postDelayed(moveSeekBarThread, 100);
mp.start();
dialog.dismiss();
}
});
mediaPlayer.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
dialog.dismiss();
}
} else {
play.setBackgroundResource(R.drawable.play);
mediaPlayer.stop();
mediaPlayer.release();
playing = false;
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
private Runnable moveSeekBarThread = new Runnable() {
public void run() {
if (mediaPlayer.isPlaying()) {
int mediaPos_new = mediaPlayer.getCurrentPosition();
int mediaMax_new = mediaPlayer.getDuration();
seekbar.setMax(mediaMax_new);
seekbar.setProgress(mediaPos_new);
handler.postDelayed(this, 1000); // Looping the thread after 1 second
}
}
};
}
Logcat 显示:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.root.music, PID: 26981
java.lang.IllegalStateException
at android.media.MediaPlayer.isPlaying(Native Method)
at com.root.music.MainActivity.run(MainActivity.java:132)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5351)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:947)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:742)
你得到 IllegalStateException .
Signals that a method has been invoked at an illegal or inappropriate time .
在 if 条件
之后调用super.onBackPressed();
@Override
public void onBackPressed()
{
if (mediaPlayer!= null)
{
if(mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.release();
}
super.onBackPressed(); // Call here
}
问题似乎是由 moveSeekBarThread
Runnable
引起的,从中引发异常,在 onBackPressed()
释放 mediaPlayer
后继续执行.这导致 isPlaying()
方法被执行,根据 documentation 将导致 IllegalStateException
:
if the internal player engine has not been initialized or has been released.
查看 moveSeekBarThread
,它似乎被配置为通过延迟将自己发送回 handler
Handler
实例来无休止地重新安排自己。当用户离开 activity 时,此过程不会停止,这解释了为什么 moveSeekBarThread
保留 运行。因此,基于以上所述,一种解决方案可能是确保在用户离开 activity 时调用 mediaPlayer.release()
之前删除 handler
队列中的任何 moveSeekBarThread
实例].
您应该可以通过在调用 mediaPlayer.release()
之前调用 handler.removeCallbacks(moveSeekBarThread);
来实现。例如如下:
@Override
public void onBackPressed() {
super.onBackPressed();
handler.removeCallbacks(moveSeekBarThread);
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
在mediaPlayer.release()
之前调用应该没问题,但我觉得不管mediaPlayer
是否在播放都调用它比较安全。这样,如果 Runnable
确实以某种方式启动或保持启动状态,尽管媒体播放器尚未启动或已停止,Runnable
仍将被清除。
顺便说一句,虽然我没有任何使用 MediaPlayer
的经验,但我偶然注意到 release
方法的文档有以下内容:
It is considered good practice to call this method when you're done using the MediaPlayer. In particular, whenever an Activity of an application is paused (its onPause() method is called), or stopped (its onStop() method is called), this method should be invoked to release the MediaPlayer object, unless the application has a special need to keep the object around. In addition to unnecessary resources (such as memory and instances of codecs) being held, failure to call this method immediately if a MediaPlayer object is no longer needed may also lead to continuous battery consumption for mobile devices, and playback failure for other applications if no multiple instances of the same codec are supported on a device.
因此,除非在您的情况下有特殊需要将媒体播放器保留在 activity 中,否则最好处理发布过程(包括从 [=18 中清除 moveSeekBarThread
=]) 在 onPause
或 onStop
中。
希望对您有所帮助!
首先你需要明白illegalStateException是什么意思:
根据 Android 文档:
It Signals that a method has been invoked at an illegal or inappropriate time. In other words, the Java environment or Java application is not in an appropriate state for the requested operation.
看看媒体播放器的状态图:
https://developer.android.com/images/mediaplayer_state_diagram.gif
调用setDataSource(FileDescriptor),或setDataSource(String),或setDataSource(Context, Uri),或setDataSource(FileDescriptor, long, long),或setDataSource(MediaDataSource)将Idle状态的MediaPlayer对象传输到初始化状态。 如果在任何其他状态下调用 setDataSource(),则会抛出 IllegalStateException。
始终注意可能从重载的 setDataSource 方法中抛出的 IllegalArgumentException 和 IOException 是一种很好的编程习惯。