这段代码可以很好地播放精美的歌曲,但有些时间会随机转到下一首歌曲会导致应用程序崩溃。随机发生
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)
答案 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
您可以绕过例外并使用它进行第二次通话。希望它可以帮助你。
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;
}
}
}
这将尝试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;
}
}
}
}
}
IllegalStateException
或prepare()
,则会引发prepareAsync()
在任何其他州被召唤。处于准备状态时,音频/音量等属性, screenOnWhilePlaying,循环可以通过调用来调整 相应的设定方法。
要开始播放,必须调用start()
。 start()
返回后
成功,MediaPlayer对象处于已启动状态。
可以调用 isPlaying()来测试MediaPlayer对象是否为
处于已启动状态。
处于“已启动”状态时,内部播放器引擎会调用用户
提供OnBufferingUpdateListener.onBufferingUpdate()
回调
如果事先已注册OnBufferingUpdateListener,则为方法
通过setOnBufferingUpdateListener(OnBufferingUpdateListener)
。这个
回调允许应用程序跟踪缓冲状态
同时播放音频/视频。调用start()
对a没有影响
已处于已启动状态的MediaPlayer对象。
应该检查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()值来检查媒体播放器是否正在播放。
答案 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();
}
});