获取mediaPlayer.getCurrentPosition时会随机出现java.lang.illegalStateException

时间:2016-06-03 05:42:30

标签: java android

这段代码可以很好地播放精美的歌曲,但有些时间会随机转到下一首歌曲会导致应用程序崩溃。随机发生

    updateSeekBar = new Thread() {
        @Override
        public void run() {
            int runtime = mediaPlayer.getDuration();
            int currentPosition = 0;
            while (currentPosition < runtime) {
                try {
                    sleep(500);
                    currentPosition = mediaPlayer.getCurrentPosition();//This is where the app crash                        
                    if (seekBar != null) {
                        seekBar.setProgress(currentPosition);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    };

崩溃报告

06-10 22:08:53.160 15351-15560/skydeveloper.me.musicx2 E/AndroidRuntime: FATAL EXCEPTION: Thread-6875
                                                                     Process: skydeveloper.me.musicx2, PID: 15351
                                                                     java.lang.IllegalStateException
                                                                         at android.media.MediaPlayer.getCurrentPosition(Native Method)
                                                                         at skydeveloper.me.musicx2.Player$1.run(Player.java:104)

7 个答案:

答案 0 :(得分:4)

实际上,如果媒体播放器处于错误状态,则会出现此问题。

如果您的MediaPlayer位于Initialized-State,则无法拨打start()。因此,您必须等到MediaPlayer处于Prepared-State位置。 您只能在准备,开始和暂停状态下寻找媒体播放器。

有关详细信息,请查看:Media Player State Diagram

您也可以拨打当前位置的第二个电话。因为它是随机问题,然后绕过并再次调用该方法可以节省您的时间。

mediaPlayer.reset();

try {
   .......
   .......
   currentPosition = mediaPlayer.getCurrentPosition();
   ......
} catch (IllegalStateException e) {
   mediaPlayer.reset();
   currentPosition = mediaPlayer.getCurrentPosition();
}

mediaPlayer.prepareAsync();

资源链接: What is this error java.lang.IllegalStateException at MediaPlayer.getCurrentPosition

UPDATE1:

您可以绕过例外并使用它进行第二次通话。希望它可以帮助你。

try {
....
currentPosition = mediaPlayer.getCurrentPosition();
....
} catch (final Exception e) {
    e.printStackTrace();
    if (e instanceof IllegalStateException) { // bypass IllegalStateException
        .......
        // You can again call the method and make a counter for deadlock situation or implement your own code according to your situation
        if (retry) {
               mediaPlayer.reset();
               currentPosition = mediaPlayer.getCurrentPosition();
        } else {
            throw e;
        }
    }
}

UPDATE2:

这将尝试3次获得当前位置。如果没有找到,那么它将给出例外。

 try {
     ....
     currentPosition = mediaPlayer.getCurrentPosition();
     ....
     } catch (final Exception e) {
         e.printStackTrace();
         if (e instanceof IllegalStateException) { // bypass IllegalStateException
             .......
             // You can again call the method and make a counter for deadlock situation or implement your own code according to your situation
             boolean checkAgain = true;
             int counter = 0;
                 for(int i = 0; i < 2; i++){
                     if (checkAgain) {
                         mediaPlayer.reset();
                         currentPosition = mediaPlayer.getCurrentPosition();
                         if(currentPosition > 0) {
                             checkAgain = false;
                             counter++;
                         }
                     } else {
                         if(counter == 0){
                             throw e;
                         }
                     }
                 }


         }
     }

UPDATE4:

  1. 如果IllegalStateExceptionprepare(),则会引发prepareAsync() 在任何其他州被召唤。
  2. 处于准备状态时,音频/音量等属性, screenOnWhilePlaying,循环可以通过调用来调整 相应的设定方法。

  3. 要开始播放,必须调用start()start()返回后 成功,MediaPlayer对象处于已启动状态。 可以调用 isPlaying()来测试MediaPlayer对象是否为 处于已启动状态。

  4. 处于“已启动”状态时,内部播放器引擎会调用用户 提供OnBufferingUpdateListener.onBufferingUpdate()回调 如果事先已注册OnBufferingUpdateListener,则为方法 通过setOnBufferingUpdateListener(OnBufferingUpdateListener)。这个 回调允许应用程序跟踪缓冲状态 同时播放音频/视频。调用start()对a没有影响 已处于已启动状态的MediaPlayer对象。

  5. 应该检查isPlaying()方法。所以代码如下所示:

     try {
         ....
         currentPosition = mediaPlayer.getCurrentPosition();
         ....
         } catch (final Exception e) {
             e.printStackTrace();
             if (e instanceof IllegalStateException) { // bypass IllegalStateException
                 .......
                 // You can again call the method and make a counter for deadlock situation or implement your own code according to your situation
                 boolean checkAgain = true;
                 int counter = 0;
                     for(int i = 0; i < 2; i++){
                         if (checkAgain) {
                             mediaPlayer.reset();
                             if(mediaPlayer != null & mediaPlayer.isPLaying()) {
                                currentPosition = mediaPlayer.getCurrentPosition();
                             } else {
                                currentPosition = 0; 
                             }
                             if(currentPosition > 0) {
                                 checkAgain = false;
                                 counter++;
                             }
                         } else {
                             if(counter == 0){
                                 throw e;
                             }
                         }
                     }
    
    
             }
         }
    

答案 1 :(得分:3)

在此代码中检查当前位置是否在结束之前,如果是,则等待500ms,此时它可能已经过了结束!事实上,出于所有实际目的,它可能会在检查后的一刻结束。这不是线程安全的,但有一些同步解决方案可以缓解这种情况。我建议你使用这样一个更简单的解决方案:

updateSeekBar = new Thread() {
        @Override
        public void run() {
            int runtime = mediaPlayer.getDuration();
            int currentPosition = 0;
            int adv = 0;
            while ((adv = ((adv = runtime - currentPosition) < 500)?adv:500) > 2) {
                try {
                    currentPosition = mediaPlayer.getCurrentPosition();
                    if (seekBar != null) {
                        seekBar.setProgress(currentPosition);
                    }
                    sleep(adv);    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (IllegalStateException e) {
                    seekBar.setProgress(runtime);
                    break;
                }

            }
        }
    };

此代码首先计算currentPosition和持续时间之间的差异,并且只有当差异超过2ms时才会尝试获取新的当前位置(2ms只是一个任意数字,可以增加一些安全余量,同时牺牲2ms的精度最后。)睡眠也会移动到循环结束,这会增加安全范围,并使搜索栏的显示更符合当前位置。最后添加了一个catch语句,以防其他所有内容都失败。

顺便说一下,虽然代码中没有显示,但我假设seekBar是final的,所以每次都不需要检查null。也许将它移到顶部并在它为空时退出。

答案 2 :(得分:2)

有可能,当你试图获得媒体播放器的位置时,播放器已经停止或释放,所以应用以下条件,

     if(mediaPlayer != null & mediaPlayer.isPLaying())
        currentPosition = mediaPlayer.getCurrentPosition();
     else 
        currentPosition = 0;

尝试以下代码,

     handler.postDelayed(new Runnable(){
        @Override
        public void run() {
            int runtime = mediaPlayer.getDuration();
            int currentPosition = 0;
            while (currentPosition < runtime) {
               try {
                    if(mediaPlayer != null & mediaPlayer.isPLaying())
                        currentPosition = mediaPlayer.getCurrentPosition();
                    else 
                       currentPosition = 0;    

                    if (seekBar != null) {
                          seekBar.setProgress(currentPosition);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
              }
          }
      }, 500);

答案 3 :(得分:1)

我认为原因是线程 .sleep()行。当媒体播放器实际上处于停止或释放状态时,它会导致当前线程进入休眠状态。

文档提到调用 getCurrentPosition()必须在其中一个有效状态下发生:

  

{闲置,初始化,准备,开始,暂停,停止,   PlaybackCompleted}

在调用getCurrentPosition之前,您可以通过检查isPlaying()值来检查媒体播放器是否正在播放。

此外,您可以使用TimerTimerTask来运行您的线程,而不是使用while循环和Thread.sleep();

答案 4 :(得分:1)

我强烈怀疑这些方法不是线程安全的。即使状态检查人们正在建议,如果您从另一个线程中交错另一个操作,使得此检查无效,您仍可能遇到问题。

考虑在媒体播放器对象上进行同步以防止并发访问。您必须声明mediaPlayer是最终的。

kill -9

之后(使用其中一个建议的支票。我没有看到这是否合适):<​​/ p>

final MediaPlayer mediaPlayer = ...

答案 5 :(得分:0)

请遵循状态图:enter image description here

您将意识到应该调用reset()以使其恢复到空闲状态。只有这样才能调用setDataSource()

答案 6 :(得分:0)

尝试一下: 将mMediaPlayer.start();替换为:

mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mediaPlayer) {
                    mMediaPlayer.start();
                }
});