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虚拟表创建、按选中日期查询父列表、按行业类型查询子列表的方法 MasterVisitPlanActivity中初始化ExpandableListView控件,自定义MyExpandableListAdapter继承SimpleCursorTreeAdapter完成数据绑定,重写getChildrenCursor方法获取子节点对应的Cursor对象
- 自定义
故障根因
异常核心原因是代码从Cursor读取数据时,目标列对应的索引值为-1,即当前Cursor的返回结果中不存在该列,和Cursor实际包含的行数、列数无直接关联。结合SimpleCursorTreeAdapter的实现要求,常见触发点有三个:
- 提供给适配器的父/子列表Cursor未包含强制要求的
_id主键列所有基于
CursorAdapter实现的适配器(含SimpleCursorTreeAdapter),内部会自动检索Cursor中名为_id的主键列,只要查询结果未返回该列,取列索引时会直接返回-1触发异常,这是这类控件最常见的踩坑点。 - 查询SQL存在列名拼写错误、漏查绑定字段的问题,比如子列表需要绑定
MVP_BRCH_CODE_NAME字段,但SELECT语句未查询该列,后续绑定阶段自然无法找到对应列。 - 重写视图绑定逻辑时硬编码了错误的列序号,未通过列名动态获取正确索引值。
修复方案
按以下步骤逐一排查修改即可解决:
- 第一步:调整所有父、子列表的查询SQL,确保返回结果必须包含
_id列
错误写法(必触发异常):
普通表正确写法:SELECT MVP_INDUSTRY_TYPE FROM plan_table WHERE visit_date = ?
如果使用的是FTS3虚拟表,可将虚拟表默认的SELECT _id, MVP_INDUSTRY_TYPE FROM plan_table WHERE visit_date = ?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
相关产品推荐
相关产品推荐

