java_lang_IllegalStateException

问题分析

当一个方法在不合法或不恰当的时间被调用时抛出。

解决方案

当一个方法在不合法或不恰当的时间被调用时抛出。建议根据状态图检查对象当前状态,更改错误的调用方法时机。

示例一

    java.lang.IllegalStateException
      at io.er.yune.MediaPlayer._reset(NativeMethod)
      at io.er.yune.MediaPlayer.reset(MediaPlayer.java:734)
      at io.er.yune.widget.VideoView.release(VideoView.java:502)
      at io.er.yune.widget.VideoView.access$1500(VideoView.java:69)
      at io.er.yune.widget.VideoView$3.surfaceDestroyed(VideoView.java:164)
      at android.view.SurfaceView.updateWindow(SurfaceView.java:594)
      at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:239)
      at android.view.View.dispatchWindowVisibilityChanged(View.java:8170)
      at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1113)
      at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1113)
      at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1113)
      at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1113)

问题分析:

这种异常是由于MediaPlayer的生命周期使用不正确,比如没有调用prepare等方法就先调用isPlaying等方法时,或非合法状态调用prepareAsyn,setDataSource方法时会抛出这种异常。

解决方案:由于MediaPlayer的生命周期使用不正确导致抛出的异常,建议阅读MediaPlayer的状态图,确认不同状态调用正确的函数。

代码示例

步骤一:初始化操作

// 方案一:通过将音频文件添加到资源结构中的res/raw文件夹中。

MediaPlayer player =MediaPlayer.create(getApplicationContext(), R.raw.music);

// 方案二:以file://开头的本地文件URI

MediaPlayer player =MediaPlayer.create(getApplicationContext(),Uri.parse(“file:///sdcard/music/1.mp3”));

// 方案三:setDataSource方法

MediaPlayer player =newMediaPlayer();
  player.setDataSource(“/sdcard/test.3gp”);
  player.prepare();

步骤二:播放控制

关键状态及函数说明:

准备好MediaPlayer后,想要开始播放,必须调用start()方法。当此方法成功返回时,MediaPlayer的对象处于Started状态。

isPlaying()方法可以被调用来测试某个MediaPlayer对象是否在Started状态。而对一个已经处于Started状态的MediaPlayer对象调用start()方法没有影响。

start()方法调用之后调用pause()方法并返回时,播放可以被暂停会使MediaPlayer对象进入Paused状态。调用start()方法会让一个处于Paused状态的MediaPlayer对象从之前暂停的地方恢复播放。当调用start()方法返回的时候,MediaPlayer对象的状态会又变成Started状态。在Started与Paused状态的相互转换在内部的播放引擎中是异步的。所以可能需要一点时间在isPlaying()方法中更新状态,若在播放流内容,这段时间可能会有几秒钟。

调用stop()方法会停止播放,并且还会让一个处于Started、Paused、Prepared或PlaybackCompleted状态的MediaPlayer进入Stopped状态。

调用seekTo()方法可以调整播放的位置。seekTo(int)方法是异步执行的,所以它可以马上返回,但是实际的定位播放操作可能需要一段时间才能完成,尤其是播放流形式的音频/视频。当实际的定位播放操作完成之后,内部的播放引擎会调用客户端程序员提供的OnSeekComplete.onSeekComplete()回调方法。可以通过setOnSeekCompleteListener(OnSeekCompleteListener)方法注册。seekTo(int)方法也可以在其它状态下调用,比如Prepared、Paused和PlaybackCompleted状态。

播放位置可以调用getCurrentPosition()方法得到,它可以帮助如音乐播放器的应用程序不断更新播放进度。

    private void startPlay() {
        player.start();
    }
    private void stopPlay() {
        payer.stop();
    }
    private void pausePlay() {
        player.pause();
    }
    private void goTo(int pos) {
       player.seekTo(pos);
    }

步骤三:释放播放资源

当播放到流的末尾,播放就完成了。如果调用了setLooping(boolean)方法开启了循环模式,那么这个MediaPlayer对象会重新进入Started状态。

在播放结束时,应调用MediaPlayerrelease()方法,释放播放程序所占用的资源。

    private void release() {
      if(player != null) {
         player.stop();
         player.release();
         player = null;
      }
    }

参考文献