删除SQLite数据库首项导致应用崩溃问题求助
问题分析与解决方案
你遇到的崩溃问题核心在于错误假设SQLite的自增主键ID会在删除条目后重新连续排序,但实际上SQLite的INTEGER PRIMARY KEY(默认自增)是不会复用或重新分配ID的——删除ID=1的条目后,剩下的条目ID依然是2,不会变成1。而你的代码通过循环i+1作为ID去调用getData(),当删除首项后,size变为1,循环i=0时会尝试查询ID=1,这个ID已经不存在,返回的Cursor是空的,此时调用cursor.moveToFirst()就会触发CursorIndexOutOfBoundsException。
至于VACUUM命令,它的作用只是整理数据库文件、回收删除数据占用的空闲空间,完全不会修改现有数据的ID值,所以对你的问题没有帮助。
解决方案:放弃“ID连续”的假设,直接遍历所有数据
最合理的做法是直接查询所有用户数据,通过遍历Cursor来获取每个条目的信息,而不是依赖i+1这种错误的ID生成逻辑。下面是修改后的代码:
1. 优化数据库访问代码
DBHelper userDB = new DBHelper(context); size = userDB.numberOfRows(); Toast.makeText(context, String.valueOf(size), Toast.LENGTH_LONG).show(); if (size > 0) { main_label.setVisibility(View.GONE); main_listView.setVisibility(View.VISIBLE); data = new String[size][2]; ids = new int[size]; // 直接查询所有用户数据,避免按错误ID查询 Cursor cursor = userDB.getReadableDatabase().rawQuery("SELECT * FROM Users", null); int index = 0; // 遍历Cursor获取每一条数据 if (cursor.moveToFirst()) { do { // 组装姓名和职位信息 String surname = cursor.getString(cursor.getColumnIndex(DBHelper.USER_COLUMN_SURNAME)); String name = cursor.getString(cursor.getColumnIndex(DBHelper.USER_COLUMN_NAME)); String jobTitle = cursor.getString(cursor.getColumnIndex(DBHelper.USER_COLUMN_JOB_TITLE)); data[index][0] = surname + " " + name + "\n" + jobTitle; // 获取手机号和ID data[index][1] = cursor.getString(cursor.getColumnIndex(DBHelper.USER_COLUMN_PHONE)); ids[index] = cursor.getInt(cursor.getColumnIndex(DBHelper.USER_COLUMN_ID)); index++; } while (cursor.moveToNext()); } // 记得关闭Cursor,避免内存泄漏 if (!cursor.isClosed()) { cursor.close(); } customAdapter = new ListAdapterUsers(context, mActivity, data, ids, size); main_listView.setAdapter(customAdapter); } else { main_label.setVisibility(View.VISIBLE); main_listView.setVisibility(View.GONE); }
2. 可选:给DBHelper增加获取完整数据的方法
为了代码更整洁,你可以在DBHelper里新增一个方法,专门返回所有用户的Cursor:
public Cursor getAllUsersFullData() { SQLiteDatabase db = this.getReadableDatabase(); // 这里也可以指定需要的列,避免查询不必要的数据 return db.rawQuery("SELECT id, name, surname, job_title, phone FROM Users", null); }
然后在访问代码里替换成:
Cursor cursor = userDB.getAllUsersFullData();
3. 额外优化:避免SQL注入风险
你当前的getData()方法用字符串拼接SQL语句,虽然ID是int类型暂时安全,但最好改成参数化查询,降低风险:
public Cursor getData(int id) { SQLiteDatabase db = this.getReadableDatabase(); // 使用占位符?,传入参数数组 return db.rawQuery("SELECT * FROM Users WHERE id=?", new String[]{String.valueOf(id)}); }
这样修改后,不管数据库里的ID是否连续,都能正确获取所有存在的用户数据,彻底解决崩溃问题。
内容的提问来源于stack exchange,提问作者mremremre1
相关产品推荐
相关产品推荐

