【问题标题】:Android SQLite cursor getType appears to be crashing appAndroid SQLite 游标 getType 似乎正在崩溃的应用程序
【发布时间】:2015-02-17 03:08:44
【问题描述】:

将临时值插入表中的所有列时,它似乎可以工作。请参阅下面的方法并在下面记录。但是当我使用下面的测试方法测试该列是否存在时,它会返回该列存在的错误!

您还可以在日志中看到 getType 为除 name 列之外的列返回 0??!!为此我在底部添加了建表方法(是的,我更新了版本号)

请注意,此问题已根据下面的 cmets 进行了编辑(因此前几个 cmets 可能没有意义)。

第一个sn-p代码来自调用下面两个方法的地方

ContentValues values = setContVal_All_Columns(myTable);

//create row
long insertId = database.insert(myTable, null, values);
System.out.println("Column date exists = " + String.valueOf(doesColumnExist(myTable,"date")));

setContVal_All_Columns 方法:

//sets generic content values to initialize row = excluding ID column
private ContentValues setContVal_All_Columns(String myTable) {

    ContentValues contentValues = new ContentValues();
    Cursor cursor = database.query(myTable,null,null,null,null,null,null);
    String[] columnNames = cursor.getColumnNames();
    cursor.moveToFirst();

    for(String name : columnNames) {
        if(!name.equals(IdColumn)) {  //excludes Id column
            int index = cursor.getColumnIndex(name);
            System.out.println("Column name = " + name + " index = " + String.valueOf(index));
            System.out.println("Type = " + String.valueOf(cursor.getType(index))); //appears to crash on the getType
            if (cursor.getType(index) == 3) {  //String
                System.out.println("Column is string");
                contentValues.put(name, " ");
            } else if (cursor.getType(index) == 1) {  //integer
                contentValues.put(name, 0);
            }
        }
    }

    return contentValues;
}

日志信息:

02-16 19:58:42.296    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Column name = date index = 1
02-16 19:58:42.296    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Type = 0
02-16 19:58:42.296    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Column name = name index = 2
02-16 19:58:42.296    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Type = 3
02-16 19:58:42.296    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Column is string
02-16 19:58:42.296    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Column name = altitude index = 3
02-16 19:58:42.296    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Type = 0
02-16 19:58:42.296    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Column name = is_used index = 4
02-16 19:58:42.296    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Type = 0
02-16 19:58:42.296    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Column name = warning index = 5
02-16 19:58:42.296    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Type = 0
02-16 19:58:42.296    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Column name = action index = 6
02-16 19:58:42.296    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Type = 0
02-16 19:58:42.316    9711-9711/com.mycompany.dudesmyreminders I/System.out﹕ Column date exists = false

编辑:测试列是否存在的方法:总是在日期列上返回 -1...

private boolean doesColumnExist(String myTable, String myColumn) {
    boolean doesExist = true;

Cursor cursor = database.rawQuery("PRAGMA table_info(" + myTable + ")",null);
cursor.moveToFirst();

int value = cursor.getColumnIndex(myColumn);

if(value == -1)
{
    doesExist = false;
}
return doesExist;
}

编辑:表创建方法:

//Database creation sql statement
private static final String SQL_CREATE_SPECIAL_DAYS =
        "CREATE TABLE " + dbFields.TABLE_NAME_SPECIAL_DAYS + " (" +
                dbFields.COLUMN_SPECIAL_DAYS_ID + INTEGER_PRIMARY_KEY + COMMA_SEP +
                dbFields.COLUMN_SPECIAL_DAYS_DATE + TEXT_TYPE + COMMA_SEP +
                dbFields.COLUMN_SPECIAL_DAYS_NAME + TEXT_TYPE + COMMA_SEP +
                dbFields.COLUMN_SPECIAL_DAYS_ALTITUDE + INTEGER_TYPE + COMMA_SEP +
                dbFields.COLUMN_SPECIAL_DAYS_USED + INTEGER_TYPE + COMMA_SEP +
                dbFields.COLUMN_SPECIAL_DAYS_WARNING + INTEGER_TYPE + COMMA_SEP +
                dbFields.COLUMN_SPECIAL_DAYS_ACTION + INTEGER_TYPE +
                // Any other options for the CREATE command
                " )";



@Override
public void onCreate(SQLiteDatabase database) {
    database.execSQL(SQL_CREATE_SPECIAL_DAYS);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    Log.w(MySQLiteHelper.class.getName(),
            "Upgrading database from version " + oldVersion + " to "
                    + newVersion + ", which will destroy all old data");
    db.execSQL("DROP TABLE IF EXISTS " + dbFields.TABLE_NAME_SPECIAL_DAYS);
    onCreate(db);
}

【问题讨论】:

  • 显示崩溃日志以及应用程序在哪一行崩溃?
  • 更新是否提供请求的日志信息?
  • 以及谷歌返回的原因:原因:android.database.CursorIndexOutOfBoundsException:请求索引-1,大小为1
  • 我注意到那行,但不知道它是什么意思。仅供参考 - 当我在尚未给出值的日期列上使用 getColumnIndex 时,即使它肯定在表中,它也会返回 -1。不确定这是否有助于解开这个谜团。请注意,“日期”列的日志中的索引显示为 1,而不是 -1。我迷路了。
  • @EdwardBagby :尝试在String[] columnNames = cursor.getColumnNames(); 行之后调用cursor.moveToFirst()

标签: android mysql sqlite


【解决方案1】:

查看原始代码块中的这段代码...

Cursor cursor = database.query(myTable,null,null,null,null,null,null);
String[] columnNames = cursor.getColumnNames();

...在执行任何游标查询时,游标“索引”(即它指向的数据集行)始终为 -1。这是索引为 0 的第一行之前(这是有原因的)。但是,此时调用 getColumNames() 是合法的,因为列名在查询过程中被单独编目,并且在游标的生命周期内保持不变。

但是,调用 getType() 确实需要光标“指向”(引用)数据集中的有效行。文档并不完全清楚,但推断这是一项要求...

API 级别 11 中添加的 public abstract int getType (int columnIndex)

返回给定列值的数据类型。 返回列的首选类型,但数据可能会转换为 get-type 方法中记录的其他类型,例如 getInt(int)、getFloat(int) 等。

换句话说,除非游标引用数据集的有效行,否则不可能获得 preferred 类型。只需将光标移动到第一行(假设它在数据集中有有效的数据行)就可以获取每列中实际数据的首选类型。

所以基本上只需在使用getType()之前添加moveToFirst()...

Cursor cursor = database.query(myTable,null,null,null,null,null,null);
String[] columnNames = cursor.getColumnNames();
if (cursor.getCount() > 0)
    cursor.moveToFirst(); // Calls to cursor.getType() will work from now on

【讨论】:

  • 关于原始崩溃原因的明确答案。说得通。现在我已经包含了 cursor.moveToFirst() ,知道为什么他们 getType 返回 0 吗??
  • 另外 - 如果您对下一个问题有任何想法,我会全力以赴:stackoverflow.com/questions/28554774/…
  • @EdwardBagby :值 0 表示 Cursor.FIELD_TYPE_NULL,这表明,即列中有一个“空”dat 值。
  • 你是说getType读取的是实际值的类型,而不是分配给列的数据类型?
  • @EdwardBagby:是的。这就是为什么它需要数据集中的有效行。例如,“null”不是表列的有效数据类型,但值可能为 null(如果允许)。 SQLite 还允许将不同的数据类型放入它们不应该放入的列中(例如,允许在 String 列中写入 1 而不是“1”)。 getType() 方法似乎有点模糊 - 文档当然是他们建议的那样,它将返回“首选”类型,但如果不同,它似乎返回实际类型。
猜你喜欢
  • 1970-01-01
  • 2016-08-10
  • 1970-01-01
  • 1970-01-01
  • 2016-12-30
  • 1970-01-01
  • 2014-04-28
  • 2017-08-02
  • 1970-01-01
相关资源
最近更新 更多