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

Android MediaPlayer播放完第二首歌曲后无响应问题如何修复?

问题原因
  • 监听丢失问题:OnCompletionListener 仅在 onCreate 中给首次初始化的MediaPlayer设置了,后续playSong方法中新建的MediaPlayer实例没有重新绑定该监听,第二首歌曲播放完成后没有触发切换逻辑,同时相关状态更新逻辑失效导致应用无响应。
  • Handler泄漏与空指针风险:onCreate中启动的循环延时任务没有做生命周期管理,MediaPlayer被释放后任务仍在执行,调用mediaPlayer.getCurrentPosition()会抛出IllegalStateException异常,触发ANR。
  • MediaPlayer操作逻辑不规范:playSong中对旧MediaPlayer的操作顺序有误,释放前没有判断实例状态,若已经处于停止/释放状态调用stop会直接崩溃。
  • 静态实例风险:MediaPlayer被声明为static,容易持有Activity上下文导致内存泄漏,也会增加状态管理混乱的概率。

修复方案

1. 新增类成员变量,统一管理循环任务和监听

private Handler seekHandler;
private Runnable seekRunnable;
// 抽成公共完成监听,避免重复编写逻辑
private MediaPlayer.OnCompletionListener completionListener = new MediaPlayer.OnCompletionListener() {
    @Override
    public void onCompletion(MediaPlayer mp) {
        if (loop) {
            playSong(position);
        } else {
            nextButton.performClick();
        }
    }
};

2. 改造onCreate中的进度更新逻辑

删除原来冗余的Player.this.runOnUiThread进度更新代码,替换为可管理的Handler循环:

// 原来的handler.postDelayed逻辑替换为下面的代码
seekHandler = new Handler();
seekRunnable = new Runnable() {
    @Override
    public void run() {
        // 增加实例状态判断,避免调用异常
        if(mediaPlayer != null && mediaPlayer.isPlaying()){
            int currentPos = mediaPlayer.getCurrentPosition();
            seekMusic.setProgress(currentPos);
            txtsstart.setText(evalTime(currentPos));
        }
        seekHandler.postDelayed(this, 500);
    }
};
seekHandler.postDelayed(seekRunnable, 500);

// 首次创建MediaPlayer后绑定公共监听
mediaPlayer.setOnCompletionListener(completionListener);

3. 重写onDestroy方法,释放资源避免泄漏

@Override
protected void onDestroy() {
    super.onDestroy();
    // 销毁时停止循环任务
    if (seekHandler != null) {
        seekHandler.removeCallbacks(seekRunnable);
        seekHandler = null;
    }
    // 释放MediaPlayer资源
    if (mediaPlayer != null) {
        if(mediaPlayer.isPlaying()){
            mediaPlayer.stop();
        }
        mediaPlayer.release();
        mediaPlayer = null;
    }
}

4. 重构playSong方法,规范操作逻辑

public void playSong(int pos){
    // 先停止当前的进度更新任务,避免操作旧实例抛出异常
    if (seekHandler != null) {
        seekHandler.removeCallbacks(seekRunnable);
    }
    // 规范释放旧MediaPlayer逻辑
    if(mediaPlayer != null){
        if(mediaPlayer.isPlaying()){
            mediaPlayer.stop();
        }
        mediaPlayer.release();
        mediaPlayer = null;
    }

    Uri u = Uri.parse(mySongs.get(pos).toString());
    mediaPlayer = MediaPlayer.create(getApplicationContext(), u);
    sname = mySongs.get(pos).getName();
    txtsname.setText(sname);

    seekMusic.setMax(mediaPlayer.getDuration());
    String endTime = evalTime(mediaPlayer.getDuration());
    txtsstop.setText(endTime);

    // 给新的MediaPlayer绑定完成监听
    mediaPlayer.setOnCompletionListener(completionListener);
    mediaPlayer.start();
    playButton.setImageResource(R.drawable.ic_pause);
    setAlbumCover();

    // 重新启动进度更新任务
    seekHandler.postDelayed(seekRunnable, 500);
}

内容的提问来源于stack exchange,提问作者Masaneo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 17:24:01