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

RecyclerView列表复用异常:滚动时TextView错乱、数据重复不完整排查

解决RecyclerView视图错乱与重复数据问题

嗨,我看了你遇到的RecyclerView滚动时内容错乱、重复数据的问题,这其实是RecyclerView适配器实现中很常见的错误——你把ViewHolder里的TextView声明成了适配器的全局成员变量,导致所有复用的视图共用同一组TextView引用,滚动时就会出现内容串位、重复的情况。另外还有几个小细节也需要调整,我来帮你一步步修正:

问题核心原因

  • 适配器类中的txtsessiontime、txtvolupload等TextView是全局成员,而非每个ViewHolder的独立引用。当RecyclerView复用视图时,这些全局变量会被新的ViewHolder覆盖,导致旧视图内容被错误更新。
  • onBindViewHolder中使用holder.getAdapterPosition()获取位置,虽然能工作,但更直接的是用方法参数里的position(适配新版本可改用holder.getBindingAdapterPosition())。
  • ViewHolder的类名View和Android系统的View类重名,容易引发混淆和潜在错误。

修正后的适配器代码

public class Adapter_Usage extends RecyclerView.Adapter<Adapter_Usage.UsageViewHolder>{
    Context context;
    ArrayList<Info_Usage> listusage;

    public Adapter_Usage(Context context, ArrayList<Info_Usage> listusage) {
        this.context = context;
        this.listusage = listusage;
    }

    @Override
    public UsageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        android.view.View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_usage, parent, false);
        return new UsageViewHolder(view);
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void onBindViewHolder(UsageViewHolder holder, int position) {
        Info_Usage infousage = listusage.get(position);
        String[] arraybilldate = infousage.strdate.split("\\s+");
        
        // 直接使用holder中的TextView引用,确保每个视图项独立绑定数据
        holder.txtusageyear.setText(arraybilldate[2]);
        holder.txtusageday.setText(arraybilldate[1]);
        holder.txtusagemon.setText(arraybilldate[0]+", ");
        holder.txtsessiontime.setText(infousage.strsessiontime);
        holder.txtvolupload.setText("Upload : "+infousage.struploads+" MB");
        holder.txtvoldownload.setText("Download : "+infousage.strdownloads+" MB");
    }

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

    // 重命名ViewHolder类,避免和系统View冲突,将TextView作为内部成员
    public class UsageViewHolder extends RecyclerView.ViewHolder {
        CustomTextView txtsessiontime, txtvolupload, txtvoldownload, txtusageyear, txtusageday, txtusagemon;

        public UsageViewHolder(android.view.View view) {
            super(view);
            txtusageyear = view.findViewById(R.id.txtusageyear);
            txtusageday = view.findViewById(R.id.txtusageday);
            txtusagemon = view.findViewById(R.id.txtusagemon);
            txtsessiontime = view.findViewById(R.id.txtsessiontime);
            txtvolupload = view.findViewById(R.id.txtvolupload);
            txtvoldownload = view.findViewById(R.id.txtvoldownload);
        }
    }
}

其他优化建议

  1. 适配器构造函数简化:你原构造函数中的int resource参数未被使用,直接移除即可。
  2. 主Activity数据更新优化:如果后续需要频繁更新列表数据,建议复用适配器对象并调用notifyDataSetChanged()通知数据更新,避免重复创建适配器实例:
// 初始化适配器(可放在Activity的onCreate方法中)
Adapter_Usage usageAdapter = new Adapter_Usage(Activity_Usage.this, listusage);
recycler.setAdapter(usageAdapter);

// 排序数据后更新视图
Collections.sort(listusage, new Comparator<Info_Usage>() {
    @Override
    public int compare(Info_Usage lhs, Info_Usage rhs) {
        int right = Integer.parseInt(rhs.getcurr());
        int left = Integer.parseInt(lhs.getcurr());
        return Integer.compare(right, left); // 用Integer.compare简化排序逻辑
    }
});

if(listusage.size() == 0) {
    recycler.setVisibility(View.GONE);
    txtnousage.setVisibility(View.VISIBLE);
} else {
    txtnousage.setVisibility(View.GONE);
    recycler.setVisibility(View.VISIBLE);
    usageAdapter.notifyDataSetChanged(); // 通知适配器数据已更新
}

修复原理说明

RecyclerView的核心是视图复用,每个ViewHolder对应一个独立的可复用视图项。将TextView放在ViewHolder内部,能保证每个复用视图都有自己的控件引用,不会互相干扰。滚动时onBindViewHolder会正确将对应位置的数据绑定到当前ViewHolder的控件上,彻底解决内容错乱、重复的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:04:29