使用SimpleCursorAdapter从SQL数据库填充ListView时程序崩溃
解决SimpleCursorAdapter填充ListView崩溃的问题
嘿,我之前做类似大学作业的时候也踩过这个坑!你的崩溃问题大概率是因为SimpleCursorAdapter有个容易被忽略的硬性要求:绑定的Cursor必须包含名为_id的主键列,这是很多新手容易漏掉的关键点。
核心问题分析
SimpleCursorAdapter内部依赖_id列来唯一标识ListView的每一行数据,如果你的数据库表没有这个列,或者列名不是严格的_id(比如写成id、task_id都不行),就会在实例化Adapter的时候直接崩溃。
看你的getAllRows函数是用SELECT *查询,那只要表结构里有_id列就没问题,但如果你的表创建时没加这个字段,那肯定会出问题。
分步解决方案
1. 检查并修正数据库表结构
打开你的DBAdapter类,找到创建表的SQL语句,确保包含_id主键字段,示例如下:
// 替换成你实际的列定义,必须保留_id字段 private static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + "_id INTEGER PRIMARY KEY AUTOINCREMENT," + // 这一行是核心要求 COLUMN_NAME + " TEXT NOT NULL," + COLUMN_DATE + " TEXT NOT NULL" + ");";
如果之前已经创建过表,需要卸载当前APP后重新运行(SQLite不会自动更新已存在的表结构)。
2. 修正getAllRows函数
不需要手动调用c.moveToFirst(),SimpleCursorAdapter会自行处理Cursor的遍历逻辑,提前移动指针可能导致数据显示异常或空指针:
public Cursor getAllRows() { String query = "SELECT * FROM " + TABLE_NAME; Cursor c = db.rawQuery(query, null); // 删掉c.moveToFirst();这一行 return c; }
3. 优化populate函数的细节
- 用
this代替getBaseContext(),Activity本身就是Context,更稳妥 - 增加Cursor为空的判断,避免空指针
- 去掉不必要的类型强转(Android API 26+支持自动转换)
private void populate(){ Cursor cursor = myDb.getAllRows(); // 空Cursor判断,避免后续崩溃 if (cursor == null || cursor.getCount() == 0) { return; } String[] backDB = new String[] {DBAdapter.COLUMN_NAME, DBAdapter.COLUMN_DATE}; int[] toView = new int[] {R.id.textViewName, R.id.textViewDate}; SimpleCursorAdapter myCursor = new SimpleCursorAdapter( this, R.layout.row_layout, cursor, backDB, toView, 0); ListView myList = findViewById(R.id.listViewTasks); myList.setAdapter(myCursor); }
4. 记得关闭Cursor避免内存泄漏
在Activity的onDestroy方法里关闭Cursor和数据库连接,防止内存泄漏:
@Override protected void onDestroy() { super.onDestroy(); if (myDb != null) { myDb.close(); } // 如果Cursor是全局变量,也要在这里关闭 // if (cursor != null && !cursor.isClosed()) { // cursor.close(); // } }
按照上面的步骤调整后,应该就能解决崩溃问题,正常显示任务列表了。
内容的提问来源于stack exchange,提问作者O'Kara
相关产品推荐
相关产品推荐

