RecyclerView中使用MediaPlayer点击不同条目同时播放,如何停止上一个再播放新的?
问题原因
你当前的代码在每个列表项执行onBindViewHolder绑定时,都会独立创建一个MediaPlayer局部实例,各个实例之间没有关联逻辑,因此点击不同条目时会各自启动播放,出现多音频同时出声的问题。
修复步骤
- 首先在Adapter类中添加全局管理变量,统一记录当前播放状态:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { // 添加以下成员变量 private MediaPlayer currentMediaPlayer; private int currentPlayPosition = -1; private ImageView currentPlayBtn; // 原有类逻辑保留 }
- 修改
onBindViewHolder中的绑定逻辑,移除局部MediaPlayer的创建和prepare操作,避免列表滚动产生大量无用实例:
@Override public void onBindViewHolder(@NonNull MyAdapter.ViewHolder viewHolder, int position) { // 先重置当前条目的播放按钮状态 if (position == currentPlayPosition) { viewHolder.play.setImageResource(R.drawable.pause); } else { viewHolder.play.setImageResource(R.drawable.play); } // 把当前position存在viewHolder的tag里,方便点击时获取 viewHolder.play.setTag(position); viewHolder.play.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int clickPosition = (int) view.getTag(); // 点击的是正在播放的条目,执行暂停逻辑 if (clickPosition == currentPlayPosition) { if (currentMediaPlayer != null && currentMediaPlayer.isPlaying()) { currentMediaPlayer.pause(); ((ImageView)view).setImageResource(R.drawable.play); currentPlayPosition = -1; } return; } // 点击的是新条目,先停止上一个播放的音频 if (currentMediaPlayer != null) { currentMediaPlayer.stop(); currentMediaPlayer.release(); // 把上一个播放按钮恢复为播放状态 if (currentPlayBtn != null) { currentPlayBtn.setImageResource(R.drawable.play); } } // 初始化新的MediaPlayer,启动播放 currentMediaPlayer = new MediaPlayer(); try { currentMediaPlayer.setDataSource(item.get(clickPosition).getAudio()); currentMediaPlayer.prepare(); currentMediaPlayer.start(); // 更新全局状态 currentPlayPosition = clickPosition; currentPlayBtn = (ImageView) view; currentPlayBtn.setImageResource(R.drawable.pause); // 监听播放完成,重置状态 currentMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { mp.release(); currentPlayBtn.setImageResource(R.drawable.play); currentPlayPosition = -1; currentMediaPlayer = null; currentPlayBtn = null; } }); } catch (IOException e) { e.printStackTrace(); // 播放出错重置状态 currentPlayPosition = -1; ((ImageView)view).setImageResource(R.drawable.play); currentMediaPlayer = null; currentPlayBtn = null; } } }); }
- 补充资源释放逻辑,在页面销毁/Adapter销毁时调用,避免内存泄漏:
public void releasePlayer() { if (currentMediaPlayer != null) { currentMediaPlayer.stop(); currentMediaPlayer.release(); currentMediaPlayer = null; currentPlayPosition = -1; currentPlayBtn = null; } }
注意事项
- 若音频文件较大,建议将
prepare()替换为prepareAsync()配合准备完成监听再启动播放,避免阻塞主线程 - 可根据需求添加播放错误监听,处理异常场景
- 列表滚动时不要重复创建MediaPlayer实例,统一用全局变量管理即可
内容的提问来源于stack exchange,提问作者ghazalia
相关产品推荐
相关产品推荐

