假设您正在尝试从Android游标的多个列中获取值(如果重要的话,我会使用SQLite)。你只关心一行,所以缓存列索引是没有意义的。您可以尝试将每列的值放在一行中,如下所示:
String value = cursor.getString(cursor.getColumnIndex(columnName));
但是,如何检测和处理光标中不存在该名称的列的情况?
We know如果发生这种情况,cursor.getColumnIndex(name)
将返回-1
。但那么cursor.getString(-1)
会做什么?您可以使用try
和catch
抛出任何异常吗?它不清楚...... documentation说,
结果以及当列值为null或列类型不是字符串类型时此方法是否抛出异常是实现定义的。
但它没有说明columnIndex
为-1的异常或其他指定行为。
我在一些设备上的测试表明你得到了这个例外:
java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.
Make sure the Cursor is initialized correctly before accessing data from it.
我们能指望抛出异常吗?
另一种方法是在调用getColumnIndex()
之前检查getString(columnIndex)
返回的索引:
columnIndex = cursor.getColumnIndex(columnName);
if (columnIndex < 0) {
// handle absence of column
} else {
value = cursor.getString(columnIndex);
}
但是每列使用那么多行看起来很冗长,并且违反了DRY原则,导致代码中出现粗心错误。
如果我们可以将代码提取到为每个列调用的单独方法中,我不会介意重复。但我没有看到任何简单的方法,因为列可以有不同的类型。 (我们可以继承CursorWrapper并实现getInt()
,getString()
等来进行我们想要的检查,从而将重复限制在专门的实用程序类中。这是我们能做的最好的吗? )
另一种方法是使用getColumnIndexOrThrow()
而不是getColumnIndex()
。这将允许您跳过保存columnIndex
的值并对其进行测试的步骤,因为如果columnIndex
为-1(并捕获它),您可以指望抛出异常。但这并没有很好地发挥作用:
如果您不确定列是否存在,请使用getColumnIndex(String)并检查-1,这比捕获异常更有效。
还有其他想法吗?有关上述想法的任何想法吗?
答案 0 :(得分:2)
是否有一种简洁,可预测的方式从a获取列值 光标?
我会说是,但这将是根据良好的设计方法,如果不能完全消除猜测/不知道列名称。也就是说,在创建Cursor之前,列名称是已知的。
但是,可能存在列名称即使是正确的,也可能导致意外结果的情况。例如,带有连接表的Cursor具有相同的列名(例如,经常使用的 _id 列)或者可能进入类似SELECT _id, _id, _id FROM cards
的精神错乱领域。在这种情况下,通过 AS 子句重命名列名将是解决方案。
但是,如何检测和处理该名称列的情况 光标中不存在?
同样,如上所述,精心设计的项目可能会完全否定发生这种情况的可能性。如果没有,那么可以使用Cursor getColumnCount
和getColumnName
方法来规避-1, IllegalStateException 条件,例如。
public boolean isColumnInCursor(String columName, Cursor csr) {
for (int i=0; i < csr.getColumnCount(); i++) {
if (csr.getColumnName(i).toLowerCase().equals(columName.toLowerCase())) {
csr.close();
return true;
}
}
csr.close();
return false;
}
示例用法是: -
Cursor csr = ex001db.getAisleAndShopsWithUniqueIDColumns();
String test_column = "Fred";
if (!ex001db.isColumnInCursor("Fred", csr)) {
Log.d("OUCH","Column " + test_column + " not in Cursor");
}
test_column = DBHlpr001.AISLENAMECOLUMN;
if (!ex001db.isColumnInCursor(test_column, csr)) {
Log.d("OUCH","Column " + test_column + " not in Cursor");
} else {
Log.d("NOT OUCH","Column " + test_column + " is in Cursor");
}
csr.close();
上面的输出是: -
09-20 13:25:35.163 4217-4217/? D/OUCH: Column Fred not in Cursor
09-20 13:25:35.164 4217-4217/? D/NOT OUCH: Column aislename is in Cursor
如果我们可以将代码提取到一个代码中,我不介意重复 为每列调用单独的方法。但我没有看到任何 这样做的简单方法,因为列可以有不同的类型。 (我们 可以子类化CursorWrapper并实现getInt(),getString()等。 做我们想要的检查,从而将重复限制在一个 专业实用班。这是我们能做的最好的吗?)
我不确定上面的代码(isColumnInCursor
方法)是否符合您的要求,尽管我很确定它符合单独的单独方法,至少是为了检测缺少的列条件。
还有其他想法吗?有关上述想法的任何想法吗?
以上!?