#android #database #sqlite #android-cursor
#Android #База данных #sqlite #android-cursor
Вопрос:
Я использую 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 или как я должен это сделать? Возможно ли это вообще и хорошая ли это идея?
Комментарии:
1. У вас есть несколько строк? Создание вашей собственной getString вызовет поиск по карте для каждого вызова, а не только для getColumnIndex .
Ответ №1:
Я наткнулся на этот вопрос в поисках наилучшего способа создать пользовательский Cursor
для использования вместе с SQLiteDatabase
. В моем случае мне нужен был дополнительный атрибут для курсора, чтобы передавать дополнительную информацию, поэтому мой вариант использования не совсем такой, как в тексте вопроса. Публикую свои выводы в надежде, что это будет полезно.
Сложность для меня заключалась в том, что методы запроса SQLiteDatabase возвращают курсор, и мне нужно было передать пользовательский подкласс Cursor.
Я нашел решение в Android API: используйте класс 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;
}
Ответ №2:
Создание вашей собственной getString вызовет поиск по карте для каждого вызова, а не только для getColumnIndex .
Вот код для SQLiteCursor.getColumnIndex и AbstractCursor.getColumnIndex. Если у вас много строк, сокращение вызовов этой функции предотвратит ненужную обработку строк и поиск по карте.
Ответ №3:
Я бы не стал его расширять, я бы создал вспомогательный:
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: если вы вызываете это в цикле, вы настраиваете себя на заметное влияние на производительность. Предпочтительный способ — выполнить поиск по индексу один раз, кэшировать его и использовать вместо этого.
Комментарии:
1. Спасибо! Похоже, это решение, которое сработает. Но возможно ли вместо этого расширить его и не использовать помощник?
2. Не совсем, поскольку экземпляр объекта создается операционной системой, а не вами, и нет способа создать подкласс курсора из другого.
Ответ №4:
Вам следует использовать статический метод DatabaseUtils.stringForQuery(), который уже есть в Android SDK, чтобы легко извлекать значение, этот пример предназначен для String
бота. существует также метод для Long
stringForQuery(SQLiteDatabase db, String query, String[] selectionArgs)
Служебный метод для запуска запроса в базе данных и возврата значения в первом столбце первой строки.
Что-то вроде
String myString=DatabaseUtils.stringForQuery(getDB(),query,selectionArgs);
Комментарии:
1. О, извините, это было не то, что мне было нужно. Мой пример был, возможно, немного простым, я добавил некоторый код, чтобы показать, что я хотел.
Ответ №5:
Наткнулся на это в поисках другого решения, но просто хочу добавить это, поскольку я считаю, что ответы неудовлетворительны.
Вы можете легко создать свой собственный класс курсора. Чтобы разрешить функциям, требующим 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 и кэшируйте его.
Извините, я не могу добавить какой-либо код в настоящее время, но я на мобильном устройстве, поэтому я попытаюсь добавить немного позже.