是否有一种简洁,可预测的方式从游标中获取列值?

时间:2017-09-19 21:29:31

标签: android sqlite cursor

假设您正在尝试从Android游标的多个列中获取值(如果重要的话,我会使用SQLite)。你只关心一行,所以缓存列索引是没有意义的。您可以尝试将每列的值放在一行中,如下所示:

String value = cursor.getString(cursor.getColumnIndex(columnName));

但是,如何检测和处理光标中不存在该名称的列的情况?

We know如果发生这种情况,cursor.getColumnIndex(name)将返回-1。但那么cursor.getString(-1)会做什么?您可以使用trycatch抛出任何异常吗?它不清楚...... 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,这比捕获异常更有效。

还有其他想法吗?有关上述想法的任何想法吗?

1 个答案:

答案 0 :(得分:2)

  

是否有一种简洁,可预测的方式从a获取列值   光标?

我会说是,但这将是根据良好的设计方法,如果不能完全消除猜测/不知道列名称。也就是说,在创建Cursor之前,列名称是已知的。

但是,可能存在列名称即使是正确的,也可能导致意外结果的情况。例如,带有连接表的Cursor具有相同的列名(例如,经常使用的 _id 列)或者可能进入类似SELECT _id, _id, _id FROM cards的精神错乱领域。在这种情况下,通过 AS 子句重命名列名将是解决方案。

  

但是,如何检测和处理该名称列的情况   光标中不存在?

同样,如上所述,精心设计的项目可能会完全否定发生这种情况的可能性。如果没有,那么可以使用Cursor getColumnCountgetColumnName方法来规避-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方法)是否符合您的要求,尽管我很确定它符合单独的单独方法,至少是为了检测缺少的列条件。

  

还有其他想法吗?有关上述想法的任何想法吗?

以上!?