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

如何判断MediaPlayer中音频轨道已结束?OnCompletionListener失效问题

解决MediaPlayer OnCompletionListener不触发的问题

你的代码里有两个关键问题导致监听器无法正常工作:

  1. 新创建的MediaPlayer未绑定监听器
    切换音频时你重新实例化了mediaPlayer,但没有给这个新对象设置OnCompletionListener——之前的监听器只绑定在旧的MediaPlayer实例上,自然不会触发。

  2. 缺少显式的setLooping(false)设置
    你提到已设置不循环,但当前代码里没有这个调用,必须显式添加到新MediaPlayer的初始化流程中。

另外,切换音频时还需要更新currentPlayingPosition,否则后续的播放/暂停逻辑会混乱。

修改后的核心代码如下:

// 统一封装监听器逻辑,避免重复代码
private MediaPlayer.OnCompletionListener completionListener = mp -> {
    audioIsFinished = true;
    releasePlayer();
    // 通过当前播放位置获取有效holder更新UI,避免复用问题
    if (currentPlayingPosition != -1) {
        ViewHolder holder = (ViewHolder) recyclerView.findViewHolderForAdapterPosition(currentPlayingPosition);
        if (holder != null) {
            holder.play.setImageResource(R.drawable.ic_baseline_play_arrow_24);
            holder.divider.setVisibility(View.INVISIBLE);
            holder.currentTime.setVisibility(View.INVISIBLE);
            holder.seekBar.setVisibility(View.INVISIBLE);
        }
    }
    currentPlayingPosition = -1;
};

holder.play.setOnClickListener(view -> {
    if(holder.getAdapterPosition() == currentPlayingPosition){
        if(mediaPlayer!=null){
            if(mediaPlayer.isPlaying()) {
                mediaPlayer.pause();
                holder.play.setImageResource(R.drawable.ic_baseline_play_arrow_24);
            }
            else {
                mediaPlayer.start();
                holder.play.setImageResource(R.drawable.ic_baseline_pause_24);
            }
        }
    }
    else{
        // 先释放旧的MediaPlayer资源
        if (mediaPlayer != null) {
            releasePlayer();
        }
        mediaPlayer = new MediaPlayer();
        fileName = notesList.get(holder.getAdapterPosition()).getPath();
        try {
            mediaPlayer.setDataSource(fileName);
            mediaPlayer.setLooping(false); // 显式设置不循环
            mediaPlayer.setOnCompletionListener(completionListener); // 绑定监听器
            mediaPlayer.prepare();
            mediaPlayer.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 更新当前播放位置标记
        currentPlayingPosition = holder.getAdapterPosition();
        holder.seekBar.setVisibility(View.VISIBLE);
        holder.divider.setVisibility(View.VISIBLE);
        holder.currentTime.setVisibility(View.VISIBLE);
        holder.seekBar.setEnabled(false);
        holder.seekBar.setProgress(0);
        holder.play.setImageResource(R.drawable.ic_baseline_pause_24);
    }
});

额外注意:

  • releasePlayer()方法要确保正确释放资源,比如调用mediaPlayer.release()并将引用置空,避免内存泄漏。
  • RecyclerView场景下不要用固定的myHolder,因为holder会被复用,通过currentPlayingPosition获取当前有效的holder才能保证UI更新正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 21:13:34