如何判断MediaPlayer中音频轨道已结束?OnCompletionListener失效问题
解决MediaPlayer OnCompletionListener不触发的问题
你的代码里有两个关键问题导致监听器无法正常工作:
新创建的MediaPlayer未绑定监听器
切换音频时你重新实例化了mediaPlayer,但没有给这个新对象设置OnCompletionListener——之前的监听器只绑定在旧的MediaPlayer实例上,自然不会触发。缺少显式的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
相关产品推荐
相关产品推荐

