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

Android RecyclerView单选按钮选中状态重复问题求助

解决RecyclerView Quiz Adapter中选项选中状态复用的问题

这个问题是RecyclerView的ViewHolder复用机制导致的典型问题,你的Adapter里有几个关键环节没处理好,才会出现选中前面题目时后面题目自动同步选中状态的情况,我来给你拆解解决方案:

问题根源

RecyclerView会复用已创建的ViewHolder来显示新的列表项,如果你没有在绑定新数据时重置View的状态(比如RadioGroup的选中状态、RadioButton的可见性),或者没有正确处理监听的重复绑定,就会出现旧的状态被带到新的列表项上,也就是你看到的第1题的选中状态被第9题(复用了第1题的ViewHolder)继承的情况。

具体修复步骤

我会针对你的Adapter代码给出修改方案,重点处理以下几个点:

1. 绑定数据前先清除旧的RadioGroup监听

ViewHolder复用时,之前设置的OnCheckedChangeListener还会保留,导致点击新选项时触发多次逻辑,甚至修改错误的Quiz对象。所以在绑定新数据前先清除旧监听:

// 在onBindViewHolder开头添加这行
holder.rg_option.setOnCheckedChangeListener(null);

2. 重置RadioButton的可见性状态

复用的ViewHolder可能之前的RadioButton被设置为GONE,所以先重置为VISIBLE,再根据当前Quiz的内容判断是否隐藏:

// 在设置选项内容前添加
holder.rb_option3.setVisibility(View.VISIBLE);
holder.rb_option4.setVisibility(View.VISIBLE);

3. 根据当前Quiz的答案恢复选中状态

每次绑定数据时,要根据当前Quiz的ans值,设置对应的RadioButton为选中状态,而不是保留上一个item的选中状态:

// 设置完选项内容后添加
int ans = quiz.getAns();
switch(ans){
    case 1:
        holder.rg_option.check(R.id.rb_option1);
        break;
    case 2:
        holder.rg_option.check(R.id.rb_option2);
        break;
    case 3:
        holder.rg_option.check(R.id.rb_option3);
        break;
    case 4:
        holder.rg_option.check(R.id.rb_option4);
        break;
    default:
        holder.rg_option.clearCheck(); // 未选中时清除状态
        break;
}

4. 移除notifyDataSetChanged()并优化选中逻辑

你之前每次选中选项都调用notifyDataSetChanged(),这会刷新整个RecyclerView,导致所有ViewHolder重新绑定,不仅性能差,还会加剧状态混乱。只需要更新当前Quiz对象并保存即可,不需要刷新列表:

// 修改OnCheckedChangeListener里的逻辑
holder.rg_option.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
        if (checkedId == -1) {
            Toast.makeText(mCtx,"No Option is selected", Toast.LENGTH_SHORT).show();
            quiz.setAns(0); // 用0标记未选中状态
        } else {
            int selectedAns = 0;
            // 用else if替代多个if,提升效率
            if(checkedId == R.id.rb_option1){
                selectedAns = 1;
            }else if(checkedId == R.id.rb_option2){
                selectedAns = 2;
            }else if(checkedId == R.id.rb_option3){
                selectedAns = 3;
            }else if(checkedId == R.id.rb_option4){
                selectedAns = 4;
            }
            quiz.setAns(selectedAns);
            // 直接保存当前quiz,不需要刷新整个列表
            Apref.getInstance(mCtx).addUpdateShoppingCartList(quiz);
        }
    }
});

5. 优化ViewHolder的创建逻辑

你之前手动设置LayoutParams的方式可以简化,inflate时传入parent参数会自动继承父布局的LayoutParams:

@NotNull
@Override
public Quiz_adapter.QuizViewHolder onCreateViewHolder(@NotNull ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(mCtx);
    // 直接传入parent,不需要手动设置LayoutParams
    View view = inflater.inflate(R.layout.cardview_quiz, parent, false);
    return new Quiz_adapter.QuizViewHolder(view);
}

修改后的完整onBindViewHolder代码

@Override
public void onBindViewHolder(QuizViewHolder holder, int position) {
    Quiz quiz = quizList.get(position);
    
    // 清除旧监听,避免复用后多次触发
    holder.rg_option.setOnCheckedChangeListener(null);
    
    // 重置RadioButton可见性
    holder.rb_option3.setVisibility(View.VISIBLE);
    holder.rb_option4.setVisibility(View.VISIBLE);
    
    // 设置题目和选项内容
    holder.txtquestion.setText(quiz.getQn());
    holder.rb_option1.setText(quiz.getOpt1());
    holder.rb_option2.setText(quiz.getOpt2());
    
    if(quiz.getOpt3().equals("")){
        holder.rb_option3.setVisibility(View.GONE);
    }else{
        holder.rb_option3.setText(quiz.getOpt3());
    }
    
    if(quiz.getOpt4().equals("")){
        holder.rb_option4.setVisibility(View.GONE);
    }else{
        holder.rb_option4.setText(quiz.getOpt4());
    }
    
    // 恢复当前题目的选中状态
    int ans = quiz.getAns();
    switch(ans){
        case 1:
            holder.rg_option.check(R.id.rb_option1);
            break;
        case 2:
            holder.rg_option.check(R.id.rb_option2);
            break;
        case 3:
            holder.rg_option.check(R.id.rb_option3);
            break;
        case 4:
            holder.rg_option.check(R.id.rb_option4);
            break;
        default:
            holder.rg_option.clearCheck();
            break;
    }
    
    // 设置新的选中监听
    holder.rg_option.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
            if (checkedId == -1) {
                Toast.makeText(mCtx,"No Option is selected", Toast.LENGTH_SHORT).show();
                quiz.setAns(0);
            } else {
                int selectedAns = 0;
                if(checkedId == R.id.rb_option1){
                    selectedAns = 1;
                }else if(checkedId == R.id.rb_option2){
                    selectedAns = 2;
                }else if(checkedId == R.id.rb_option3){
                    selectedAns = 3;
                }else if(checkedId == R.id.rb_option4){
                    selectedAns = 4;
                }
                quiz.setAns(selectedAns);
                Apref.getInstance(mCtx).addUpdateShoppingCartList(quiz);
            }
        }
    });
}

总结

通过以上修改,你就能解决选中第1题时第9题自动选中的问题,核心就是在ViewHolder复用的时候,正确重置View的状态和监听,避免旧状态被带到新的列表项上。同时移除不必要的全列表刷新,提升Adapter的性能和稳定性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 21:07:33