Ответ 1
Вы не должны получать это сообщение, если закрываете Cursor
в onStop()
или onDestroy()
. Повторите попытку. Или вызовите startManagingCursor()
после получения Cursor
из вашего запроса, и Android закроет Cursor
самостоятельно.
Я получаю "Завершение курсора, который не был деактивирован или закрытой "ошибкой на этом фрагменте кода. Код используется для заполнения списка.
Поскольку это нефатальная ошибка, нет сбоя, и все, кажется, работает отлично.. но мне не нравится ошибка.
Если я закрою курсор в конце этого кода. пустой. если я закрою курсор в onStop, я получаю ту же ошибку.
Как это исправить?
private void updateList() {
DBAdapter db = new DBAdapter(this);
db.open();
//load all waiting alarm
mCursor=db.getTitles("state<2");
setListAdapter(new MyCursorAdapter(this, mCursor));
registerForContextMenu(getListView());
db.close();
}
error :
E/Cursor ( 2318): Finalizing a Cursor that has not been deactivated
or closed. database = /data/data/xxxxxxxxxxxxxxx.db, table = alerts,
query = SELECT _id, alert_id,
E/Cursor ( 2318):
android.database.sqlite.DatabaseObjectNotClosedException: Application
did not close the cursor or database
object that was opened here
E/Cursor ( 2318): at
android.database.sqlite.SQLiteCursor.<init>(SQLiteCursor.java:210)
E/Cursor ( 2318): at
android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:
53)
E/Cursor ( 2318): at
android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:
1345)
E/Cursor ( 2318): at
android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:
1229)
....
....
Вы не должны получать это сообщение, если закрываете Cursor
в onStop()
или onDestroy()
. Повторите попытку. Или вызовите startManagingCursor()
после получения Cursor
из вашего запроса, и Android закроет Cursor
самостоятельно.
Скотт,
Я столкнулся с той же проблемой, что и вы. Прежде чем закрыть базу данных, т.е. "Db.close()," убедитесь, что ваши курсоры закрыты первыми, то есть "mCursor.close()"
Так же:
private void updateList()
{
DBAdapter db = new DBAdapter(this);
db.open();
//load all waiting alarm
mCursor=db.getTitles("state<2");
setListAdapter(new MyCursorAdapter(this, mCursor));
registerForContextMenu(getListView());
// Let close the cursor.
mCursor.close();
db.close();
}
Вы упомянули, что если вы закрыли курсор, ваш список останется пустым. Я рекомендую передать информацию в класс и скопировать ее (выделить память), затем закрыть курсор.
Когда запрос возвращает курсор, он фактически позиционируется "до" первого запись в курсор. Адаптер попытается выполнить "getItem" на первом , поэтому он будет терпеть неудачу, поскольку курсор не расположен ни на одном.
В моих базовых адаптерах я делаю курсорMoveToPosition на getViews. Это кажется для устранения необходимости перехода вперед.
Не используйте startManagingCursor(), поскольку это уже не рекомендуемый подход. Проблема возникает из-за того, что соединение курсора/БД все еще не закрывается к тому времени, когда финализатор доберется до этого объекта. Вы можете избежать этого, либо позволяя загрузчику управлять курсором, либо самостоятельно отслеживать все соединения курсора /DB/SQLiteOpenHelper и очищать их после.
Использование Loader довольно громоздко и требует много движущихся частей для его работы в сочетании с утверждением списка. С другой стороны, отслеживание ваших курсоров и соединений с базой данных подвержено человеческой ошибке. Если количество объектов курсора/БД низкое, я бы рекомендовал последнее решение. Если нет, позвольте загрузчику обрабатывать ваши соединения.
Закройте объект курсора, где бы вы его не создавали.
Когда вы создаете объект курсора и выполняете его с помощью таблицы SQLite, закройте его после его использования. Это закрытие курсора предотвращает исключение в logcat.
У вас не будет никаких исключений, связанных с завершением открытия курсора.
Эта фиксированная проблема в моем приложении.
Я боролся с этой проблемой в течение двух дней. Я пытался получить образец кода, который передавал курсор, возвращаемый из запроса базы данных, непосредственно в Адаптер списка - без промежуточного адаптера. Он отказался работать - просто отобразил пустой экран - пока я не вывел 'moveToFirst()' на курсор, прежде чем передавать его в ListAdapter. Иди цифра! Когда я прокомментирую это, он ломается.
Просто подумал, что я поделюсь этим, чтобы спасти людей той же борьбой, что и я.
Если кто-то может пролить свет на то, почему это так, я был бы признателен. Мне не приходилось ссылаться на moveToFirst на курсоры до сих пор, чтобы заставить их нормально работать.
У меня была такая же проблема, и я подумал, чтобы вы знали - на всякий случай....
Я случайно вызвал свою процедуру выборки два раза и, таким образом, "потерял" полученный курсор первого вызова. Это вызвало ошибку.
У меня тоже были проблемы с закрытием курсора:
Закрытие курсора сразу после установки адаптера просмотра списка заставляет курсор закрываться до отображения данных.
Нельзя использовать startManagingCursor для управления курсором, потому что он устарел.
Новая замена cursorLoader для startManagingCursor кажется излишней.
Перемещение позиции курсора, как было предложено, не работает.
Сделать задачу внутренним классом активности и закрывать курсор в действии метод onDestroy работает иногда, но не все время.
Выполнение задачи является внутренним классом активности и закрытием курсора в методе onStop.
Я также узнал, что я могу закрыть базу данных и открыть помощник sqlite перед закрытием курсора. Я могу даже закрыть их сразу после установки адаптера просмотра списка. Данные будут отображаться.
startManagingCursor (курсор);
Это устранило мою проблему