【问题标题】:Android MediaPlayer : IllegalStateException when app closes/press back buttonAndroid MediaPlayer:应用程序关闭/按下后退按钮时出现 IllegalStateException
【发布时间】:2017-03-28 23:14:20
【问题描述】:

我正在使用媒体播放器从 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$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)

【问题讨论】:

  • 你的isPlaying()方法在哪里?
  • 在我看来,您的 Runnable 在您致电 mediaPlayer.release() 后正在触发。如果在onBackPressed() 中调用mediaPlayer.release() 之前调用handler.removeCallbacks(moveSeekBarThread);,问题是否仍然存在?
  • if (mediaPlayer!= null){ if(mediaPlayer.isPlaying()) mediaPlayer.stop(); mediaPlayer.release(); } super.onBackPressed();
  • 感谢小丑。它工作了,现在没有崩溃。正如你所说,这是runnable的问题。您可以将其发布为答案吗?
  • @clownba0t 描述得很好。发布为答案。

标签: android android-mediaplayer illegalstateexception


【解决方案1】:

首先你需要了解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) 将处于 Idle 状态的 MediaPlayer 对象转移到 Initialized 状态. 如果在任何其他状态下调用 setDataSource(),则会引发 IllegalStateException。

始终注意可能从重载的 setDataSource 方法抛出的 IllegalArgumentException 和 IOException 是一种很好的编程习惯。

【讨论】:

  • 我不确定这是否完全正确。 onBackPressed 的实现,至少在 API 24 上的 Activity 中,似乎安排了 Activity 实例的完成。因此,调用 super 之后的代码仍然会在 Activity 完成之前运行,这意味着媒体播放器仍然会停止并释放。 OP 面临的问题的根本原因似乎是 Runnable 在发布后正在触摸媒体播放器,这是一个不同的问题。我认为将呼叫位置更改为super 不会解决这种情况下的问题。
【解决方案2】:

该问题似乎是由moveSeekBarThread Runnable 引起的,从该处引发异常,在mediaPlayeronBackPressed() 中释放后继续执行。这导致isPlaying() 方法被执行,根据documentation 将导致IllegalStateException

如果内部播放器引擎尚未初始化或已发布。

查看moveSeekBarThread,它似乎被配置为通过延迟将自己发布回handler Handler 实例来无休止地重新安排自己。当用户离开活动时,这个过程并没有停止,这解释了为什么moveSeekBarThread 继续运行。因此,基于上述情况,一种解决方案可能是确保在用户离开活动时调用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 方法的文档有以下说法:

当您使用完 MediaPlayer 后调用此方法被认为是一种很好的做法。特别是,每当应用程序的 Activity 暂停(调用其 onPause() 方法)或停止(调用其 onStop() 方法)时,应调用此方法以释放 MediaPlayer 对象,除非应用程序有特殊的需要保持对象周围。除了占用不必要的资源(例如内存和编解码器的实例)外,如果不再需要 MediaPlayer 对象,则未能立即调用该方法还可能导致移动设备持续消耗电池,如果没有,其他应用程序播放失败一台设备支持同一编解码器的多个实例。

因此,除非有特殊需要在您的情况下将媒体播放器保留在活动中,否则最好在onPause 或@987654348 中处理发布过程(包括从handler 清除moveSeekBarThread) @ 代替。

希望有帮助!

【讨论】:

    【解决方案3】:

    您将收到 IllegalStateException

    表示方法已被非法或不适当地调用 时间。

    if条件后调用super.onBackPressed();

     @Override 
    public void onBackPressed() 
     {
          if (mediaPlayer!= null)
         {
                 if(mediaPlayer.isPlaying())
                  mediaPlayer.stop();
                  mediaPlayer.release();
          }
    
         super.onBackPressed(); // Call here
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-01-02
      • 1970-01-01
      • 2016-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-10
      相关资源
      最近更新 更多