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

删除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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 22:22:59