Android MediaPlayer:当应用关闭/按下后退按钮时出现IllegalStateException

时间:2016-11-15 06:41:55

标签: android android-mediaplayer illegalstateexception

我使用媒体播放器从网址流式传输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)

3 个答案:

答案 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,这是一种很好的编程习惯。