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

Android SQLite查询语句正确但Cursor为空问题求助

Android SQLite查询Cursor.getCount()始终为0,但DB Browser执行相同语句正常的问题

我正在开发一个帮朋友祖母管理糖尿病的App:用户输入血糖值(cukier),程序自动获取检测时间(godzina),返回对应的胰岛素类型(insulina)、剂量(dawka)及采血部位(cialo)等结果(wynik)。不过遇到了一个奇怪的问题,想请大家帮忙看看。

相关代码片段

(注:变量未遵循英文命名规范,因项目为快速开发)

public Wynik getData(int pomiar, int godzina) { 
    Wynik wynik = null; 
    String query = "SELECT * FROM " + "insulina" + " WHERE godzina = " + godzina + " AND cukier = " + pomiar; 
    SQLiteDatabase db = this.getReadableDatabase(); 
    try (Cursor cursor = db.rawQuery(query, null)) { 
        Log.i("tag", "cursor length:" + cursor.getCount()); 
        if (cursor.getCount() > 0) { 
            String s = DatabaseUtils.dumpCursorToString(cursor); 
            Log.d("s", s); 
            cursor.moveToFirst(); 
            wynik = new Wynik (
                cursor.getInt(cursor.getColumnIndexOrThrow("godzina")), 
                cursor.getString(cursor.getColumnIndexOrThrow("insulina")), 
                cursor.getInt(cursor.getColumnIndexOrThrow("dawka")), 
                cursor.getString(cursor.getColumnIndexOrThrow("cialo"))
            ); 
        } 
        cursor.close(); 
        return wynik; 
    }
}

数据库结构说明

insulina表包含以下字段:

  • godzina:整数类型,存储检测时间(例:18)
  • cukier:整数类型,存储血糖值(例:10)
  • insulina:字符串类型,胰岛素类型
  • dawka:整数类型,胰岛素剂量
  • cialo:字符串类型,采血部位

问题详情

举个例子,当血糖值为10、检测时间取最近的18点时,生成的查询语句是:

SELECT * FROM insulina WHERE godzina = 18 AND cukier = 10

我在DB Browser for SQLite里执行这条语句能得到正确结果,但在App中执行时,Cursor.getCount()始终返回0,Android Studio已经提示数据库成功打开,我实在找不到问题所在,急需大家的帮助!


可能的排查方向和解决方案

嘿,我来帮你梳理下可能的原因和解决办法:

  1. 确认App使用的数据库和DB Browser打开的是同一个文件
    Android的SQLite数据库默认存在/data/data/[你的应用包名]/databases/目录下,很多时候我们会把预填充的数据库文件复制到这个路径,但如果操作失误,App连接的可能是空的/未填充的数据库,而你在DB Browser里打开的是本地的原始文件。你可以通过Android Studio的Device File Explorer找到App的数据库文件,导出后用DB Browser打开,看看里面有没有数据。

  2. 改用参数化查询避免拼接错误
    直接拼接SQL语句很容易因为类型转换、空格或者隐形字符导致查询异常,而且还存在SQL注入风险。把你的查询改成参数化形式试试:

public Wynik getData(int pomiar, int godzina) { 
    Wynik wynik = null; 
    // 使用占位符?代替直接拼接变量
    String query = "SELECT * FROM insulina WHERE godzina = ? AND cukier = ?"; 
    SQLiteDatabase db = this.getReadableDatabase(); 
    // 将变量作为字符串数组传入,rawQuery会自动处理类型转换
    try (Cursor cursor = db.rawQuery(query, new String[]{String.valueOf(godzina), String.valueOf(pomiar)})) { 
        Log.i("tag", "cursor length:" + cursor.getCount()); 
        if (cursor.moveToFirst()) { // 建议用moveToFirst替代getCount判断,更高效
            wynik = new Wynik (
                cursor.getInt(cursor.getColumnIndexOrThrow("godzina")), 
                cursor.getString(cursor.getColumnIndexOrThrow("insulina")), 
                cursor.getInt(cursor.getColumnIndexOrThrow("dawka")), 
                cursor.getString(cursor.getColumnIndexOrThrow("cialo"))
            ); 
        } 
        return wynik; 
    }
}

另外,try-with-resources语法会自动关闭Cursor,所以不需要手动调用cursor.close(),避免重复关闭导致异常。

  1. 打印完整的SQL语句对比
    在执行查询前,把生成的SQL语句打印出来,和你在DB Browser里执行的完全对比:
Log.d("DebugSQL", "执行的SQL:" + query);

看看打印出来的语句是不是和你手动执行的一模一样,比如有没有可能pomiar或者godzina传入的数值和你预期的不一样?

  1. 确认数据库初始化/预填充是否成功
    如果你的数据库是需要预填充数据的,检查初始化逻辑是否正确执行,比如在SQLiteOpenHelper的onCreate或onUpgrade里有没有正确导入数据,或者复制数据库文件的代码有没有报错。

内容的提问来源于stack exchange,提问作者Damian Ziółkowski

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:35:10