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

嵌套RecyclerView水平滚动报Inconsistency detected异常如何解决?

根因分析

你遇到的崩溃本质是嵌套RecyclerView复用过程中,子RecyclerView的数据集和布局记录的条目数量不一致触发的校验错误,具体由以下几个错误写法共同导致:

  • 子RecyclerView的LayoutManager、Adapter每次在onBindViewHolder中重复创建,复用ViewHolder时会直接重置子RV的布局状态,滚动过程中很容易出现时序错位
  • 使用全局/外层Adapter的成员变量存储子Adapter的数据集repsForEachSet,不同行绑定ViewHolder时会互相覆盖这个变量的值,子Adapter持有的数据集会被意外修改,导致布局计算时实际条目数和预期不符
  • 子RecyclerView默认开启的条目预取功能在嵌套滚动场景下,会提前计算还未绑定的ViewHolder的条目位置,数据集突变时就会触发下标越界
可行解决方案

按优先级依次修改即可解决崩溃:

  1. 将子RecyclerView的初始化逻辑全部挪到ViewHolder的构造方法中执行,onBindViewHolder仅做数据更新,不要每次重新设置LayoutManager和Adapter
  2. 禁止使用全局变量存储子Adapter的数据集,每一行绑定的时候单独生成当前行的数据集实例,子Adapter自己持有独立的数据集,避免不同行的数据互相影响
  3. 关闭子水平RecyclerView的预取功能,在子LayoutManager初始化时调用setItemPrefetchEnabled(false)即可针对性解决GapWorker预取抛出的崩溃
修改后代码示例

首先是ViewHolder改造:

public class WorkoutInterfaceViewHolder extends RecyclerView.ViewHolder {
    TextView numberOfSets;
    RecyclerView ChildRV;
    WorkoutInterfaceAdapter_Child childAdapter;

    public WorkoutInterfaceViewHolder(@NonNull View itemView) {
        super(itemView);
        numberOfSets = itemView.findViewById(R.id.your_textview_id);
        ChildRV = itemView.findViewById(R.id.child_recyclerview);
        // 初始化仅执行一次
        LinearLayoutManager childLayoutManager = new LinearLayoutManager(itemView.getContext(), LinearLayoutManager.HORIZONTAL, false);
        childLayoutManager.setItemPrefetchEnabled(false); // 关闭子RV预取
        ChildRV.setLayoutManager(childLayoutManager);
        ChildRV.setHasFixedSize(true);
        childAdapter = new WorkoutInterfaceAdapter_Child(itemView.getContext());
        ChildRV.setAdapter(childAdapter);
    }
}

然后是外层Adapter的onBindViewHolder改造:

@Override
public void onBindViewHolder(@NonNull WorkoutInterfacesAdapter.WorkoutInterfaceViewHolder holder, int position) {
    // 每次bind单独获取当前数据,不要复用全局的reps、weights变量
    List<String> reps = stringToArraylist(workout.numberOfReps);
    List<String> weights = stringToArraylist(workout.weights);
    try {
        holder.numberOfSets.setText("Set No#" + (position + 1) + ": " + weights.get(position));
        // 生成当前行独有的reps列表,不要赋值给全局变量
        List<Integer> currentReps = setCurrentRepsArray(reps.get(position));
        // 调用子Adapter的更新方法传入当前行数据
        holder.childAdapter.updateData(currentReps, workout, position);
    } catch (Exception e) {
        holder.numberOfSets.setText("Set No#" + (position + 1));
    }
}

最后给子Adapter新增数据更新方法:

// 子Adapter内部新增updateData方法
public void updateData(List<Integer> repsList, Workout workoutData, int parentPos) {
    // 子Adapter自己持有独立的数据集,不要和外部共用可变列表
    this.repsForEachSet = repsList;
    this.workout = workoutData;
    this.parentPosition = parentPos;
    notifyDataSetChanged();
}
额外注意事项
  • 确保setCurrentRepsArray方法每次返回新的ArrayList实例,不要复用同一个全局List对象,避免多个子Adapter共用同一份数据集
  • 如果外层列表需要更新数据,优先使用notifyItemChanged、notifyItemRangeInserted等局部更新方法,减少全局notifyDataSetChanged的使用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 05:45:02