我使用媒体播放器从网址流式传输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$4.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)
答案 0 :(得分:1)
您正在 IllegalStateException 。
表示某个方法已被非法或不合适地调用 时间。
在 if 条件
之后致电 @Override
public void onBackPressed()
{
if (mediaPlayer!= null)
{
if(mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.release();
}
super.onBackPressed(); // Call here
}
{{1}}
答案 1 :(得分:1)
该问题似乎是由moveSeekBarThread
Runnable
引起的,从中引发了异常,并在mediaPlayer
中释放onBackPressed()
后继续执行。这导致执行isPlaying()
方法,根据documentation将导致IllegalStateException
:
如果内部播放器引擎尚未初始化或已被释放。
查看moveSeekBarThread
,似乎已将其配置为通过将自身重新发布回handler
Handler
实例而无休止地重新安排自己。当用户离开活动时,此过程不会停止,这解释了moveSeekBarThread
继续运行的原因。因此,基于上述情况,一种解决方案可以是确保在用户离开活动时调用moveSeekBarThread
之前删除handler
队列中的mediaPlayer.release()
的任何实例
您应该可以在拨打handler.removeCallbacks(moveSeekBarThread);
之前致电mediaPlayer.release()
来执行此操作。例如,如下:
@Override
public void onBackPressed() {
super.onBackPressed();
handler.removeCallbacks(moveSeekBarThread);
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
应该可以在mediaPlayer.release()
之前调用它,但我认为无论mediaPlayer
是否正在播放,都可以更安全地调用它。这样,如果尽管媒体播放器未启动或已被停止,Runnable
确实以某种方式启动或保持启动,Runnable
仍将被清除。
顺便说一句,虽然我没有MediaPlayer
的任何经验,但我偶然注意到release
方法的文档有如下说法:
在您使用MediaPlayer完成后调用此方法被认为是一种好习惯。特别是,每当应用程序的Activity暂停(调用其onPause()方法)或停止(调用其onStop()方法)时,应调用此方法以释放MediaPlayer对象,除非应用程序具有特殊功能需要保持对象周围。除了持有不必要的资源(例如内存和编解码器实例)之外,如果不再需要MediaPlayer对象,则无法立即调用此方法也可能导致移动设备的电池持续消耗,如果没有则会导致其他应用程序的播放失败设备支持相同编解码器的多个实例。
因此,除非有特殊需要让媒体播放器保持在您的案例活动中,否则最好在{{处理moveSeekBarThread
中的handler
{}发布过程1}}或onPause
代替。
希望有所帮助!
答案 2 :(得分:0)
首先,您需要了解 illegalStateException 的含义:
根据Android文档:
它表示在非法或不适当的时间调用了某个方法。换句话说,Java环境或Java应用程序未处于所请求操作的适当状态。
查看媒体播放器的状态图:
https://developer.android.com/images/mediaplayer_state_diagram.gif
调用setDataSource(FileDescriptor),或setDataSource(String),或setDataSource(Context,Uri)或setDataSource(FileDescriptor,long,long)或setDataSource(MediaDataSource)将处于空闲状态的MediaPlayer对象传输到Initialized状态。 如果在任何其他状态下调用setDataSource(),则抛出IllegalStateException。
总是注意可能从重载的setDataSource方法抛出的IllegalArgumentException和IOException,这是一种很好的编程习惯。