Android: как создать свой собственный класс курсора? - PullRequest
6 голосов
/ 12 апреля 2011

Я использую Sqlite в Android и для получения значения из базы данных я использую что-то вроде этого:

Cursor cursor = sqliteDatabase.rawQuery("select title,category from table", null);

int columnIndexTitle = cursor.getColumnIndex("title");
iny columnIndexCategory = cursor.getColumnIndex("category");

cursor.moveToFirst();
while (cursor.moveToNext()) {
    String title = cursor.getString(columnIndexTitle);  
    String category = cursor.getString(columnIndexCategory);    
}
cursor.close();

Я хочу создать свой собственный Курсор, чтобы я мог делать getColumnIndex() и getString() одним методом. Как то так:

String title = cursor.getString("title");

Я хочу создать свой собственный класс, который расширяет курсор, который я получаю из sqliteDatabase.rawQuery, но я не уверен, как этого добиться. Должен ли я расширить SQLiteCursor или как это сделать? Это вообще возможно и это хорошая идея?

Ответы [ 5 ]

4 голосов
/ 10 ноября 2014

Я столкнулся с этим вопросом в поисках лучшего способа создания пользовательского Cursor для использования вместе с SQLiteDatabase.В моем случае мне понадобился дополнительный атрибут к Курсору для переноса дополнительной части информации, поэтому мой вариант использования не совсем такой, как в основной части вопроса.Публикация моих результатов в надежде, что это будет полезно.

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

Iнашел решение в API Android: используйте класс CursorWrapper .Кажется, он предназначен именно для этого.

Класс:

public class MyCustomCursor extends CursorWrapper {

    public MyCustomCursor(Cursor cursor) {
        super(cursor);
    }

    private int myAddedAttribute;

    public int getMyAddedAttribute() {
        return myAddedAttribute;
    }

    public void setMyAddedAttribute(int myAddedAttribute) {
        this.myAddedAttribute = myAddedAttribute;
    }

}

Использование:

public MyCustomCursor getCursor(...) {
    SQLiteDatabase DB = ...;
    Cursor rawCursor = DB.query(...);
    MyCustomCursor myCursor = new MyCustomCursor(rawCursor);
    myCursor.setMyAddedAttribute(...);
    return myCursor;
}
3 голосов
/ 12 апреля 2011

Создание собственного getString приведет к поиску карты для каждого вызова, а не только для getColumnIndex.

Вот код для SQLiteCursor.getColumnIndex и AbstractCursor.getColumnIndex . Если у вас много строк, сокращение вызовов этой функции предотвратит ненужную обработку строк и поиск по карте.

2 голосов
/ 12 апреля 2011

Я бы этого не продлил, я бы сделал помощника:

class MartinCursor {
    private Cursor cursor;

    MartinCursor(Cursor cursor) {
        this.cursor = cursor;
    }

    String getString(String column) {
        ....
    }
}

или

class MartinCursorHelper {
    static String getString(Cursor cursor, String column) {
        ....
    }
}

Лично я бы сделал последнее, если вы не противдополнительный аргумент все время.

РЕДАКТИРОВАТЬ: я забыл упомянуть важный момент pydave: если вы вызываете это в цикле, вы настраиваете себя на заметное снижение производительности.Предпочтительным способом является поиск индекса один раз, кеширование и использование его вместо этого.

0 голосов
/ 28 сентября 2014

Наткнулся на это в поисках другого решения, но просто хочу добавить это, так как я считаю, что ответы неудовлетворительны.

Вы можете легко создать свой собственный класс курсора. Чтобы позволить функциям, требующим, чтобы Cursor принимал его, он должен расширять AbstractCursor. Чтобы преодолеть проблему, когда система не использует ваш класс, вы просто делаете свой класс оберткой.

Здесь действительно хороший пример. https://android.googlesource.com/platform/packages/apps/Contacts/+/8df53636fe956713cc3c13d9051aeb1982074286/src/com/android/contacts/calllog/ExtendedCursor.java

public class ExtendedCursor extends AbstractCursor {
/** The cursor to wrap. */
private final Cursor mCursor;
/** The name of the additional column. */
private final String mColumnName;
/** The value to be assigned to the additional column. */
private final Object mValue;
/**
 * Creates a new cursor which extends the given cursor by adding a column with a constant value.
 *
 * @param cursor the cursor to extend
 * @param columnName the name of the additional column
 * @param value the value to be assigned to the additional column
 */
public ExtendedCursor(Cursor cursor, String columnName, Object value) {
    mCursor = cursor;
    mColumnName = columnName;
    mValue = value;
}
@Override
public int getCount() {
    return mCursor.getCount();
}
@Override
public String[] getColumnNames() {
    String[] columnNames = mCursor.getColumnNames();
    int length = columnNames.length;
    String[] extendedColumnNames = new String[length + 1];
    System.arraycopy(columnNames, 0, extendedColumnNames, 0, length);
    extendedColumnNames[length] = mColumnName;
    return extendedColumnNames;
}

Это общее представление о том, как это будет работать.

Теперь к сути проблемы. Чтобы предотвратить снижение производительности, создайте хэш для хранения индексов столбцов. Это будет служить кешем. Когда вызывается getString, проверьте хеш для индекса столбца. Если он не существует, извлеките его с помощью getColumnIndex и кэшируйте его.

Извините, я не могу добавить какой-либо код в настоящее время, но я нахожусь на мобильном телефоне, поэтому я постараюсь добавить его позже.

0 голосов
/ 12 апреля 2011

Вы должны использовать статический метод DatabaseUtils .stringForQuery (), который уже есть в Android SDK, для простого извлечения значения, этот пример предназначен для бота String, также есть метод для Long

stringForQuery(SQLiteDatabase db, String query, String[] selectionArgs)

Утилита для запуска запроса к БД и возврата значения в первом столбце первой строки.

Что-то вроде

String myString=DatabaseUtils.stringForQuery(getDB(),query,selectionArgs);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...