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

RecyclerView音频播放冲突问题求助:多音频同时播放

解决RecyclerView音频同时播放的问题

我来帮你搞定这个多个音频同时播放的bug!问题出在你的Adapter里每次点击播放按钮都会创建一个新的MediaPlayer实例,之前正在播放的MediaPlayer没有被停止和释放,所以就会出现两首音频同时响的情况。

下面是具体的修复方案,我会一步步说明关键修改点:

核心修改思路

  • 维护一个全局的MediaPlayer实例(或者在Adapter里保留当前播放的实例),每次播放新音频前先停止并释放旧的实例
  • 记录当前正在播放的音频位置,适配RecyclerView的ViewHolder复用特性,避免按钮状态错乱
  • 正确管理MediaPlayer的生命周期,及时释放资源

修改后的完整代码

public class AdapterSong extends RecyclerView.Adapter<AdapterSong.viewHolder> {
    Context context;
    List<ModelSong> model;
    String url_audio;
    MediaPlayer mediaplayer;
    // 记录当前正在播放的音频位置
    private int currentPlayingPosition = -1;

    public AdapterSong(Context context, List<ModelSong> model) {
        this.context = context;
        this.model = model;
    }

    @NonNull
    @Override
    public AdapterSong.viewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rec_song, parent, false);
        return new AdapterSong.viewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull final AdapterSong.viewHolder holder, final int position) {
        final ModelSong data = model.get(position);
        holder.tittle.setText(data.getTittle());

        // 根据当前播放位置更新按钮状态
        if (currentPlayingPosition == position) {
            holder.play.setVisibility(View.GONE);
            holder.stop.setVisibility(View.VISIBLE);
        } else {
            holder.play.setVisibility(View.VISIBLE);
            holder.stop.setVisibility(View.GONE);
        }

        holder.play.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    // 先停止并释放之前的MediaPlayer
                    if (mediaplayer != null) {
                        mediaplayer.stop();
                        mediaplayer.release();
                        mediaplayer = null;
                    }

                    url_audio = "http://kanoonmedia.ir/files/sorod/" + data.getFile();
                    mediaplayer = new MediaPlayer();
                    mediaplayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                    mediaplayer.setDataSource(url_audio);
                    mediaplayer.setLooping(true);
                    mediaplayer.prepare();

                    // 更新当前播放位置并刷新UI
                    int previousPosition = currentPlayingPosition;
                    currentPlayingPosition = position;
                    notifyItemChanged(previousPosition);
                    notifyItemChanged(currentPlayingPosition);

                    holder.play.setVisibility(View.GONE);
                    holder.stop.setVisibility(View.VISIBLE);
                    mediaplayer.start();
                } catch (IllegalArgumentException | SecurityException | IllegalStateException | IOException e) {
                    e.printStackTrace();
                }
            }
        });

        holder.stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mediaplayer != null) {
                    mediaplayer.stop();
                    mediaplayer.release();
                    mediaplayer = null;
                }
                // 重置当前播放位置并刷新UI
                currentPlayingPosition = -1;
                notifyItemChanged(position);
            }
        });
    }

    @Override
    public int getItemCount() {
        return model.size();
    }

    // 页面销毁时调用,释放MediaPlayer资源避免内存泄漏
    public void releaseMediaPlayer() {
        if (mediaplayer != null) {
            mediaplayer.stop();
            mediaplayer.release();
            mediaplayer = null;
            currentPlayingPosition = -1;
        }
    }

    public class viewHolder extends RecyclerView.ViewHolder {
        TextView tittle;
        CircleImageView play, stop;

        public viewHolder(View itemView) {
            super(itemView);
            tittle = itemView.findViewById(R.id.txt_tittle_song);
            play = itemView.findViewById(R.id.img_play_song);
            stop = itemView.findViewById(R.id.img_stop_song);
        }
    }
}

关键修改点说明

  1. 新增currentPlayingPosition变量:用来记录当前正在播放的音频在列表中的位置,解决ViewHolder复用导致的按钮状态显示错误
  2. 播放前检查并释放旧实例:每次点击新的播放按钮时,先停止并释放之前的MediaPlayer,确保同一时间只有一个音频在播放
  3. 主动刷新UI状态:播放或停止操作后,调用notifyItemChanged刷新对应item的按钮显示,保证状态同步
  4. 新增资源释放方法:在Activity/Fragment的onDestroy生命周期中调用releaseMediaPlayer,避免MediaPlayer内存泄漏

另外,额外提一句:如果你的音频播放需求比较复杂,建议考虑使用ExoPlayer替代原生MediaPlayer,它在多音频管理、生命周期适配方面会更专业稳定哦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:07:50