You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:26:50