Вызов SQL для getType () и getColumnNames () перед сбоем moveToNext () в Android? - PullRequest
1 голос
/ 22 марта 2019

Мне было интересно, можно ли было вызвать getType () и getColumnNames () перед moveToNext ().

В основном я пытаюсь написать следующие вспомогательные функции:

 public static int getColumnIndex(Cursor c, String columnName) {
    for (int i = 0; i < c.getColumnNames().length; i++) {
        String realName = c.getColumnName(i);
        if (realName.substring(realName.indexOf(".") + 1).equals(columnName)) {
            return i;
        }
    }
    return -1;
}

public static Object getSQLValue(Cursor c, String columnName) {
    int index = getColumnIndex(c, columnName);
    if (index > -1) {
        switch (c.getType(index)) {
            case Cursor.FIELD_TYPE_BLOB:
                return c.getBlob(index);
            case Cursor.FIELD_TYPE_FLOAT:
                return c.getFloat(index);
            case Cursor.FIELD_TYPE_STRING:
                return c.getString(index);
            case Cursor.FIELD_TYPE_INTEGER:
                return c.getInt(index);
            case Cursor.FIELD_TYPE_NULL:
                return null;
        }
    }

    return null;
}

Но иногда я получаю сообщение об ошибке (исходит от бета-тестеров, чья база данных не используется совместно со мной ...) в c.getType (index), где index равен 0, а размер c равен 0:

 Caused by android.database.CursorIndexOutOfBoundsException
    Index 0 requested, with a size of 0

Поскольку getColumnIndex должен возвращать -1 в случае проблем, как getColumnIndex может возвращать 0 и в то же время c не иметь столбца с индексом 0?Можно ли быть уверенным, что «moveToNext ()» не вызывается до этого?

Спасибо.

1 Ответ

1 голос
/ 23 марта 2019

Короче говоря, вы не можете получить тип столбца, если не переместитесь в допустимую строку, и это дополнительно требует, чтобы у самого курсора были строки.

Поэтому вам необходимо

  1. проверьте, что на самом деле курсор имеет 1 или более строк (то есть он не пустой).Для этого можно использовать метод Cursor getCount(), который возвращает int .

  2. перемещение в допустимую строку и для корректности перемещенияназад к строке, курсор был ранее расположен на.

Таким образом, я считаю, что вам будет нужно следующее: -

public static Object getSQLValue(Cursor c, String columnName) {
    Log.d("CURSORCOUNT","Cursor has a size of " + String.valueOf(c.getCount())); //<<<<<<<<<< for demo //TODO remove me
    Object rv = null;
    int rowcount = c.getCount();
    if (rowcount < 1) {
        return rv;
    }
    int index = getColumnIndex(c, columnName);
    int pos = c.getPosition();
    boolean moveback = false;
    if (pos < 0 || pos >= rowcount) {
        c.moveToFirst();
        moveback = true;
    }
    if (index > -1) {
        switch (c.getType(index)) {
            case Cursor.FIELD_TYPE_BLOB:
                rv = c.getBlob(index);
                break;
            case Cursor.FIELD_TYPE_FLOAT:
                rv = c.getFloat(index);
                break;
            case Cursor.FIELD_TYPE_STRING:
                rv = c.getString(index);
                break;
            case Cursor.FIELD_TYPE_INTEGER:
                rv = c.getInt(index);
                break;
        }
    }
    if(moveback) c.moveToPosition(pos);
    return rv;
}
  • Примечаниевышеупомянутое было исправлено, чтобы удовлетворить сохранению положения.Если курсор был перемещен в строку (см. Курсор c3 в тестировании), то эта позиция строки будет использоваться для извлечения данных / типа.Однако, если курсор находится перед первым или после первого ряда, то выполняется перемещение в первый ряд, и позиция восстанавливается до возврата.

Проверка

Предполагая, что БД с таблицей и метод getRows , который имеет логический параметр - если false, то все строки в таблице извлекаются через Курсор - если true, тогда возвращается пустой Курсор

Для проверки используется следующее: -

public class MainActivity extends AppCompatActivity {

    DBHelper mDBHlpr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mDBHlpr = new DBHelper(this); //<<<<<<<<<< The Database Helper
        mDBHlpr.getWritableDatabase().delete(DBHelper.TBL_MYTABLE,null,null); //<<<<<<<<<< empty table
        // Add some testing data
        mDBHlpr.insert("2019-03-25T19:19:39.664Z");
        mDBHlpr.insert("\"2019-03-25T19:19:39.664Z\"");

        // Get a populated cursor (c1) and and empty cursor (c2)
        Cursor c1 = mDBHlpr.getRows(false); //<<<<<<<<<< populated
        Cursor c2 = mDBHlpr.getRows(true); //<<<<<<<<< empty
        Cursor c3 = mDBHlpr.getRows(false); //<<<<<<<<<< populated for position preservation example 
        c3.moveToPosition(1); //<<<<<<<<<< moved to 2nd row

        // Try with a non-existant column for the populated cursor
        logit(DBHelper.getSQLValue(c1,"NOTACOLUMN"),"TEST1 - NOT A COLUMN");
        // Try with a valid column for the populated cursor
        logit(DBHelper.getSQLValue(c1,DBHelper.COL_MYTABLE_MYSTRING),"TEST2 - VALID COLUMN");
        // Try with a non-existant column for the empty cursor
        logit(DBHelper.getSQLValue(c2,"NOTACOLUMN"),"TEST3 - NOT A COLUMN - EMPTY CURSOR");
        // Try with a valid column for the empty cursor
        logit(DBHelper.getSQLValue(c2,DBHelper.COL_MYTABLE_MYSTRING),"TEST4 - VALID COLUMN - EMPTY CURSOR");


        //PRESERVATION OF POSITION EXAMPLE 
        // Try with a valid column for the populated cursor
        logit(DBHelper.getSQLValue(c3,DBHelper.COL_MYTABLE_MYSTRING),"TEST2 - VALID COLUMN");
        Log.d("PRESERVED_POS", "Position is " + String.valueOf(c3.getPosition()));
    }

    private void logit(Object o,String tag) {
        String msg = "OBJECT IS NULL!!!!";
        if (o != null) {
            msg = "OBJECT IS " + o.toString();
        }
        Log.d(tag,msg);
    }
}

Результат

03-23 13:19:36.175 20570-20570/? D/CURSORCOUNT: Cursor has a size of 2
03-23 13:19:36.176 20570-20570/? D/TEST1 - NOT A COLUMN: OBJECT IS NULL!!!!
03-23 13:19:36.176 20570-20570/? D/CURSORCOUNT: Cursor has a size of 2
03-23 13:19:36.176 20570-20570/? D/TEST2 - VALID COLUMN: OBJECT IS 2019-03-25T19:19:39.664Z
03-23 13:19:36.176 20570-20570/? D/CURSORCOUNT: Cursor has a size of 0
03-23 13:19:36.176 20570-20570/? D/TEST3 - NOT A COLUMN - EMPTY CURSOR: OBJECT IS NULL!!!!
03-23 13:19:36.176 20570-20570/? D/CURSORCOUNT: Cursor has a size of 0
03-23 13:19:36.176 20570-20570/? D/TEST4 - VALID COLUMN - EMPTY CURSOR: OBJECT IS NULL!!!!



03-23 13:19:36.176 20570-20570/? D/CURSORCOUNT: Cursor has a size of 2
03-23 13:19:36.176 20570-20570/? D/TEST2 - VALID COLUMN: OBJECT IS "2019-03-25T19:19:39.664Z"
03-23 13:19:36.176 20570-20570/? D/PRESERVED_POS: Position is 1

Важно, что не существует исключения, где было бы исключение, и какв последних двух строках позиция Курсора сохраняется.

  • Обратите внимание , что каждая отдельная комбинация строки / столбца может иметь свой собственный тип и исключение.столбца rowid или его псевдонима (значение может быть только целым числом для такого столбца ), любой тип значения может быть сохранен в любом типе столбца.

  • Примечание getInt может не получить все значения правильно, так как тип столбца INTEGER может хранить 64-битные значения со знаком, поэтому в некоторых случаях getLong может потребоваться для получения допустимых значений.Точно так же для предотвращения потери точности может потребоваться getDouble вместо getFloat .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...