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

RecyclerView触发IndexOutOfBoundsException异常排查求助

解决RecyclerView的IndexOutOfBoundsException异常(日期筛选场景)

咱们先来梳理下你遇到的问题:

选择Toolbar上的「指定日期」筛选选项,弹出日期选择器后,RecyclerView没有数据填充,触摸屏幕直接崩溃,抛出java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder异常;但升序、降序筛选时一切正常。

这个异常本质是RecyclerView的数据源和Adapter的状态不一致,结合你的场景和代码,我整理了针对性的修复方案:

一、核心问题分析

  1. 数据源更新不规范:日期筛选后请求新数据时,可能没有清空旧数据,导致新旧数据混杂,Adapter无法正确识别有效position;
  2. Adapter通知时机错误:每次添加单条数据就调用notifyDataSetChanged(),容易引发状态不一致;
  3. ViewHolder池操作不当:调用mMessagesView.getRecycledViewPool().clear()可能破坏RecyclerView的ViewHolder管理逻辑;
  4. 空数据未处理:日期筛选后如果后端返回空数据,RecyclerView触摸时会尝试访问无效的position。

二、针对性修复步骤

1. 规范数据源更新逻辑

在接收新的订单数据前,先清空旧数据源,避免新旧数据冲突。修改你的orderCompletedData监听逻辑:

private Emitter.Listener orderCompletedData = new Emitter.Listener() {
    @Override
    public void call(final Object... args) {
        if(getActivity() != null) {
            getActivity().runOnUiThread(() -> {
                JSONArray object1 = (JSONArray) args[0];
                if(object1 != null){
                    JSONArray array = object1.optJSONArray(0);
                    // 第一步:清空旧数据,保证数据源纯净
                    mMessages.clear();
                    int arraylength = array.length();
                    for(int j=0; j<array.length();j++){
                        JSONObject item = array.optJSONObject(j);
                        // 补全你的数据解析逻辑(这里假设你能从item中取出对应字段)
                        String orderId = item.optString("order_id");
                        String order = item.optString("order");
                        String currencyname = item.optString("currencyname");
                        String amount = item.optString("amount");
                        String filledAmount = item.optString("filledAmount");
                        String proceeds = item.optString("proceeds");
                        String orderPrice = item.optString("orderPrice");
                        String orderDate = item.optString("orderDate");
                        String orderType = item.optString("orderType");
                        
                        // 添加单条数据到数据源
                        addMessage(orderId, order, currencyname, amount, filledAmount, proceeds, orderPrice, orderDate, orderType);
                    }
                    // 统一通知Adapter更新,避免重复通知
                    mAdapter.notifyDataSetChanged();
                } else {
                    // 如果后端返回空数据,清空数据源并通知
                    mMessages.clear();
                    mAdapter.notifyDataSetChanged();
                }
            });
        }
    }
};

同时修改addMessage方法,移除里面的notifyDataSetChanged():

private void addMessage(String orderId,String order,String currencyname,String amount,String filledAmount,String proceeds,String orderPrice,String orderDate,String orderType) {
    mMessages.add(new PendingOrderModel.Builder(PendingOrderModel.RECEIVER)
            .orderid(orderId).order(order).amount(amount).currencyname(currencyname)
            .filledamount(filledAmount).orderprice(orderPrice).proceeds(proceeds)
            .orderdate(orderDate).ordertype(orderType).build());
    // 这里不再单独通知,统一在循环结束后调用notifyDataSetChanged()
}

2. 日期筛选后重置数据源

当用户选择完日期后,先清空旧数据再请求新数据,避免旧数据残留:

// 示例:日期选择完成后的回调方法(你需要根据自己的日期选择器逻辑调整)
private void onDateConfirmed(String selectedDate) {
    filterDateString = selectedDate;
    filterString = "date_specified"; // 记得设置对应的筛选类型,和后端约定好
    // 先清空旧数据并通知Adapter
    mMessages.clear();
    mAdapter.notifyDataSetChanged();
    // 重新请求筛选后的数据
    mSocket.emit("fetch_pending_orders", getSendMessageString(""));
}

3. 修复Adapter实例不一致问题

你的代码在onAttach和onViewCreated中都初始化了mAdapter,这会导致多个Adapter实例共存,状态混乱。建议只在onViewCreated中初始化:

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    // 移除这里的mAdapter初始化代码,统一在onViewCreated中处理
    if (context instanceof Activity) {
    }
}

4. 移除不当的RecycledViewPool操作

删除addMessage中的mMessagesView.getRecycledViewPool().clear();,这个操作会干扰RecyclerView的ViewHolder复用机制,容易引发状态异常。

5. 在Adapter中处理空数据

修改PendingOrderAdapter,添加空数据和无效position的判断,避免触摸空列表崩溃:

@Override
public int getItemCount() {
    // 确保数据源不为空时返回长度,否则返回0
    return mMessages != null ? mMessages.size() : 0;
}

@Override
public void onBindViewHolder(@NonNull PendingOrderViewHolder holder, int position) {
    // 校验数据源和position的有效性
    if (mMessages == null || position >= mMessages.size()) {
        holder.itemView.setVisibility(View.GONE);
        return;
    }
    // 正常绑定数据的逻辑
    PendingOrderModel model = mMessages.get(position);
    // ... 绑定数据到ViewHolder
}

6. 优化Fragment生命周期管理

在Fragment销毁时解绑Socket监听,避免内存泄漏和无效回调:

@Override
public void onDestroy() {
    super.onDestroy();
    if (mSocket != null) {
        mSocket.off("pending_orders_data", orderCompletedData);
        mSocket.disconnect();
    }
}

三、额外检查点

  • 确认日期筛选时filterString和filterDateString的参数正确,和后端约定一致,避免后端返回错误或空数据;
  • 确保所有修改数据源和通知Adapter的操作都在UI线程执行(你的代码已经用runOnUiThread,这点保持即可)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:45:18