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

RecyclerView中使用MediaPlayer点击不同条目同时播放,如何停止上一个再播放新的?

问题原因

你当前的代码在每个列表项执行onBindViewHolder绑定时,都会独立创建一个MediaPlayer局部实例,各个实例之间没有关联逻辑,因此点击不同条目时会各自启动播放,出现多音频同时出声的问题。

修复步骤
  1. 首先在Adapter类中添加全局管理变量,统一记录当前播放状态:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    // 添加以下成员变量
    private MediaPlayer currentMediaPlayer;
    private int currentPlayPosition = -1;
    private ImageView currentPlayBtn;

    // 原有类逻辑保留
}
  1. 修改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;
            }
        }
    });
}
  1. 补充资源释放逻辑,在页面销毁/Adapter销毁时调用,避免内存泄漏:
public void releasePlayer() {
    if (currentMediaPlayer != null) {
        currentMediaPlayer.stop();
        currentMediaPlayer.release();
        currentMediaPlayer = null;
        currentPlayPosition = -1;
        currentPlayBtn = null;
    }
}
注意事项
  • 若音频文件较大,建议将prepare()替换为prepareAsync()配合准备完成监听再启动播放,避免阻塞主线程
  • 可根据需求添加播放错误监听,处理异常场景
  • 列表滚动时不要重复创建MediaPlayer实例,统一用全局变量管理即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 03:24:02