onPause()事件中mediaPlayer.getCurrentPosition()引发应用崩溃问题
解决SeekBar与MediaPlayer在onPause()时崩溃的问题
我来帮你搞定这个崩溃问题!从你给出的代码片段来看,核心问题出在更新SeekBar的线程没有在onPause时及时停止,还在持续调用MediaPlayer的方法,而此时MediaPlayer的状态已经变化(比如被暂停),导致抛出异常。下面是具体的修复方案:
一、先明确问题根源
- 你的
updateSeekBar线程在Activity进入后台(onPause)后,还在循环执行mediaPlayer.getCurrentPosition(),但此时MediaPlayer可能已经被暂停、甚至后续会被释放,调用它的方法就会触发IllegalStateException。 - 另外
isOnPause变量如果没有用volatile修饰,子线程可能看不到主线程修改的状态值,导致循环停不下来。
二、具体修复步骤
1. 修正状态变量的可见性
给isOnPause加上volatile修饰,保证主线程修改后,子线程能立刻看到最新值:
private volatile boolean isOnPause = false;
2. 在onPause()中正确停止线程与MediaPlayer
在Activity进入后台时,标记暂停状态,暂停MediaPlayer,并中断更新线程:
@Override protected void onPause() { super.onPause(); isOnPause = true; // 暂停MediaPlayer(如果正在播放) if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.pause(); } // 中断更新线程,强制它退出循环 if (updateSeekBar != null) { updateSeekBar.interrupt(); } }
3. 完善线程的异常处理与状态检查
在更新线程的run方法里,增加MediaPlayer状态检查,同时捕获中断和状态异常,避免崩溃:
updateSeekBar = new Thread() { @Override public void run() { // 先判断MediaPlayer是否初始化成功 if (mediaPlayer == null) return; int totalDuration = mediaPlayer.getDuration(); int currentPosition = 0; while (currentPosition < totalDuration && !isOnPause) { try { // 每次循环都检查MediaPlayer的状态,避免调用无效方法 if (mediaPlayer != null && mediaPlayer.isPlaying()) { currentPosition = mediaPlayer.getCurrentPosition(); // 用Message.obtain()复用消息对象,更高效 Message message = Message.obtain(); message.what = currentPosition; handler.sendMessage(message); } Thread.sleep(500); } catch (InterruptedException e) { // 捕获线程中断异常,直接退出循环 break; } catch (IllegalStateException e) { // 捕获MediaPlayer状态异常,打印日志后退出 e.printStackTrace(); break; } } } };
4. 在onResume()中恢复播放与线程
当Activity回到前台时,恢复状态,重新启动MediaPlayer和更新线程:
@Override protected void onResume() { super.onResume(); isOnPause = false; if (mediaPlayer != null && !mediaPlayer.isPlaying()) { mediaPlayer.start(); // 重新创建并启动更新线程 updateSeekBar = new Thread(() -> { if (mediaPlayer == null) return; int totalDuration = mediaPlayer.getDuration(); int currentPosition = mediaPlayer.getCurrentPosition(); while (currentPosition < totalDuration && !isOnPause) { try { if (mediaPlayer != null && mediaPlayer.isPlaying()) { currentPosition = mediaPlayer.getCurrentPosition(); Message message = Message.obtain(); message.what = currentPosition; handler.sendMessage(message); } Thread.sleep(500); } catch (InterruptedException | IllegalStateException e) { break; } } }); updateSeekBar.start(); } }
5. 在onDestroy()中彻底释放资源
最后在Activity销毁时,彻底停止线程并释放MediaPlayer,避免内存泄漏:
@Override protected void onDestroy() { super.onDestroy(); isOnPause = true; // 停止并清空线程 if (updateSeekBar != null) { updateSeekBar.interrupt(); updateSeekBar = null; } // 释放MediaPlayer if (mediaPlayer != null) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } }
三、额外注意事项
- 永远不要在子线程中直接操作UI,你用Handler发送消息更新SeekBar的方式是正确的,继续保持。
- 调用MediaPlayer的任何方法前,都要先检查它是否为null、是否处于合法状态(比如是否已初始化、是否已准备好),这能避免大部分状态异常。
内容的提问来源于stack exchange,提问作者KOUAKOU
相关产品推荐
相关产品推荐

