Android Nougat 中的 SQLite 查询不向后兼容

SQLite query in Android Nougat is not backwards compatible

我有一个 SQLite 查询 不是 return _id 在 Android 牛轧糖上的记录但是 return Android pre-Nougat 的记录。

当我将调试器附加到 Nougat 模拟器并开始四处寻找时,我观察到以下情况:

原码

readableDatabase.query("report_view", null, "_id = ?", new String[]{"2016309001"}, null, null, null).getCount()

结果:0

四处寻找/评估表达式

readableDatabase.rawQuery("SELECT * FROM report_view WHERE _id = 2016309001", null).getCount()

结果:1

启用 SQLite 日志会导致(注意单引号):

V/SQLiteStatements: /data/user/0/xyz/bla.db: "SELECT * FROM report_view WHERE _id = '2016309001'"

对于牛轧糖上的非原始查询。我似乎无法在 pre-Nougat (Marshmallow) 设备上启用 SQLite 日志。

看来问题是由 Android 用单引号将参数括起来引起的。 _id 列的类型为 integer。并且用引号括起来的值是 string 类型。为什么这突然成为牛轧糖的一个问题?

从理论上讲,SQLite 的行为不应该有所不同。您使用的 table 定义可能会导致不同的 affinity.

反正你给query函数的参数是字符串,所以数据库处理成字符串也就不足为奇了

如果你想给数据库一个数字,你必须让参数成为一个数字。 而 Android 框架不允许大多数数据库函数这样做,因此您必须将其直接放入字符串中:

db.query("report_view", null, "_id = " + "2016309001", null, null, null, null).getCount();

请注意,有一个 helper function 用于计算行数:

DatabaseUtils.queryNumEntries(db, "report_view", "_id = " + "2016309001");

除非我弄错了,否则您的原始代码将日期参数显式地作为字符串 (new String[]) 传递,并且 Android 查询方法的文档,selectioArgs 参数状态

selectionArgs String: You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they appear in the selection. The values will be bound as Strings.

所以如果你想要字符串以外的东西,你应该执行强制转换,或者更好的是,不要使用查询和 rawQuery 方法,而是使用准备好的语句 (SQLiteStatement),这将允许你指定参数类型。

还有'?'在日志中被替换应该是一个 "fake" 用于日志目的的替换(至少我希望它是一个用于日志目的的假替换,因为 Android 应该在那里使用绑定参数,而不是替换它查询)。

最后 Android 中的字段类型仅用于 type affinity,因此即使您在 table 中将字段声明为 "integer" 也是完全有可能的,如果您使用了 Query 方法及其仅包含字符串的参数,您实际上在记录中得到了字符串。