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

Android SQLite绑定ExpandableListView报Cursor列-1读取失败错误

问题现象

Android应用开发中,将SQLite数据绑定到ExpandableListView时运行抛出如下异常:

Failed to read row 0, column -1 from a CursorWindow which has 1 rows, 9 columns

实现逻辑说明:

  • 父列表逻辑:根据用户选中日期做筛选,展示MVP_INDUSTRY_TYPE列内容
  • 子列表逻辑:展示对应父分组下的MVP_BRCH_CODE_NAME、MVP_BRCH_ADDRESS列内容
  • 已完成代码:
    • 自定义DataBaseHelper类继承SQLiteOpenHelper,实现FTS3虚拟表创建、按选中日期查询父列表、按行业类型查询子列表的方法
    • MasterVisitPlan Activity中初始化ExpandableListView控件,自定义MyExpandableListAdapter继承SimpleCursorTreeAdapter完成数据绑定,重写getChildrenCursor方法获取子节点对应的Cursor对象
故障根因

异常核心原因是代码从Cursor读取数据时,目标列对应的索引值为-1,即当前Cursor的返回结果中不存在该列,和Cursor实际包含的行数、列数无直接关联。结合SimpleCursorTreeAdapter的实现要求,常见触发点有三个:

  1. 提供给适配器的父/子列表Cursor未包含强制要求的_id主键列

    所有基于CursorAdapter实现的适配器(含SimpleCursorTreeAdapter),内部会自动检索Cursor中名为_id的主键列,只要查询结果未返回该列,取列索引时会直接返回-1触发异常,这是这类控件最常见的踩坑点。

  2. 查询SQL存在列名拼写错误、漏查绑定字段的问题,比如子列表需要绑定MVP_BRCH_CODE_NAME字段,但SELECT语句未查询该列,后续绑定阶段自然无法找到对应列。
  3. 重写视图绑定逻辑时硬编码了错误的列序号,未通过列名动态获取正确索引值。
修复方案

按以下步骤逐一排查修改即可解决:

  • 第一步:调整所有父、子列表的查询SQL,确保返回结果必须包含_id列
    错误写法(必触发异常):
    SELECT MVP_INDUSTRY_TYPE FROM plan_table WHERE visit_date = ?
    
    普通表正确写法:
    SELECT _id, MVP_INDUSTRY_TYPE FROM plan_table WHERE visit_date = ?
    
    如果使用的是FTS3虚拟表,可将虚拟表默认的docid字段映射为_id:
    SELECT docid AS _id, MVP_INDUSTRY_TYPE, MVP_BRCH_CODE_NAME, MVP_BRCH_ADDRESS FROM plan_fts_table WHERE visit_date MATCH ?
    
  • 第二步:检查getChildrenCursor方法实现,确保子Cursor查询逻辑正确
    参考正确实现:
    @Override
    protected Cursor getChildrenCursor(Cursor groupCursor) {
        // 从父Cursor中读取当前分组的行业类型值,列名注意和表结构完全一致
        String industryType = groupCursor.getString(groupCursor.getColumnIndexOrThrow("MVP_INDUSTRY_TYPE"));
        // 调用DB方法查询子列表,确保返回结果包含_id和所有需要绑定的字段
        Cursor childCursor = dbHelper.getChildList(selectedDate, industryType);
        // 必须给子Cursor设置通知Uri,避免数据刷新不同步
        childCursor.setNotificationUri(getContentResolver(), DBConfig.CONTENT_URI);
        return childCursor;
    }
    
  • 第三步:所有Cursor取值逻辑禁止硬编码列序号,统一使用getColumnIndexOrThrow(列名)动态获取索引,开发阶段如果列名写错会直接抛出明确的“列不存在”异常,方便快速定位问题,不会抛出模糊的-1索引错误。
  • 第四步:检查适配器构造时传入的列名绑定参数,确保传入的组、子列名数组和Cursor返回的字段名完全一致,大小写、拼写不能有偏差:
    // 父布局绑定配置:列名数组和父Cursor返回字段对应
    String[] groupFrom = new String[]{"MVP_INDUSTRY_TYPE"};
    int[] groupTo = new int[]{R.id.tv_industry_name};
    // 子布局绑定配置:列名数组和子Cursor返回字段对应
    String[] childFrom = new String[]{"MVP_BRCH_CODE_NAME", "MVP_BRCH_ADDRESS"};
    int[] childTo = new int[]{R.id.tv_branch_name, R.id.tv_branch_address};
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 18:15:58