Несколько вопросов о курсорах базы данных SQLite в Android

Чтобы реализовать доступ к базе данных в своем приложении, я следовал руководству Ларса Фогеля, но я очень запутался в нескольких вещах...

1) Каждый раз при вызове fetchTodo будет создаваться и возвращаться новый курсор. Оставить предыдущий курсор для сборщика мусора. Итак, если я не использую startManagingCursor или даже CursorLoader в этом отношении, должен ли я вызывать .close() для курсора, когда я закончу с ним? Конечно, за рамками fetchTodo, пример:

Cursor cursor = mNotesAdapter.fetchTodo();
// do something...
cursor.close();

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

2) Cursor также имеет метод .deactivate(), и в документации сказано, что он использует меньше ресурсов (чем активные курсоры). Когда именно я должен использовать это? Например, в моем приложении у меня есть ListActivity, который заполняется через SimpleCursorAdapter (инициализация кода для этого вызывается только один раз). Используемый курсор является переменной-членом класса, потому что он нужен мне вне метода, который заполняет список. Мне нужно, чтобы он запрашивал базу данных, когда что-то из нее удалялось. Но до тех пор, пока запись не будет удалена, что является действием пользователя и может занять некоторое время, должен ли я тем временем деактивировать курсор? Потому что он снова будет активен, когда я снова позвоню .requery(). Или SimpleCursorAdapter перестанет работать, потому что курсор не активен?

EDIT: я только что проверил это и обнаружил, что не могу вызвать deactivate() после настройки адаптера курсора. Список будет пустым, если курсор не активен, поэтому он должен оставаться активным до тех пор, пока отображается ListActivity. В конце концов, мы должны просто позволить StartManagingCursor разобраться с этим. Или новый CursorLoader.

3) Я знаю, что startManagingCursor/stopManagingCursor устарели, но я не ориентируюсь на Honeycomb (по крайней мере, на данный момент) и пока не хочу иметь дело с новым CursorLoader. Но в приведенном выше руководстве startManagingCursor используется везде, а stopManagingCursor ни разу не вызывается. Почему нет? Android справляется с этим по-своему? В любой ситуации я должен позвонить stopManagingCursor?


person rfgamaral    schedule 29.09.2011    source источник


Ответы (1)


Изменить: обновленный ответ, чтобы отразить обновленный вопрос 1:

1) При каждом вызове fetchTodo будет создаваться и возвращаться новый курсор. Оставить предыдущий курсор для сборщика мусора. Итак, если я не использую startManagingCursor или даже CursorLoader в этом отношении, должен ли я вызывать .close() для курсора, когда я закончу с ним?

Да, вы обязательно должны сказать Android startManagingCursor(), использовать LoaderManager/CursorLoader или close() самостоятельно. Невыполнение этого требования приведет к утечке памяти, GC не поможет с этим, поскольку за Cursor есть собственные ресурсы (например, дескрипторы файлов в базе данных).

2) Курсор также имеет метод .deactive(), и в документации говорится, что он использует меньше ресурсов (чем активные курсоры). Когда именно я должен использовать это? ...

EDIT для других читателей: ОП нашел ответ и разместил его в своем вопросе. Следующее остается в силе:

Я никогда не использовал deactivate() (нет deactive()), может быть, кто-нибудь еще объяснит это. Если вам нужны действительно безболезненные запросы/обновления, ознакомьтесь с фреймворком LoaderManager — он не только для Honeycomb: с помощью библиотеки совместимости вы можете использовать LoaderManagerFragments) вплоть до Android 1.6. Вам не только нужно написать меньше кода, но и полностью разгрузить эти вещи для Android, в гораздо большей степени, чем startManagingCursor().

EDIT2: некоторые примечания по LoaderManager

На сайте developer.android.com есть LoaderManager руководств, но они довольно... сложны и трудны для понимания с первого раза, как и большинство руководств. Мне также пришлось много копать, лучшая универсальная остановка, которую я нашел до сих пор, это http://mobile.tutsplus.com/tutorials/android/android-sdk_loading-data_cursorloader/ (плюс все источники javadocs и compat lib, которые вы можете найти) --- способ работы LoaderManager очень похож к управляемым диалогам (теперь также устаревшим, замененным на DialogFragment) с их методами onCreateDialog, onPrepareDialog, где вы просто говорите Android «показать диалог № 123», а затем Android вызывает ваш код с этим идентификатором; то же самое для загрузчиков: «загрузить загрузчик № 123», Android вызывает onCreateLoader().

Единственным очевидным недостатком изначально было то, что LoaderManager сильно зависит от фреймворка ContentProvider, и некоторым людям это действительно не нравится. Конечно, это дополнительное обучение и код, но если у вас есть ContentProvider для ваших собственных данных (даже если они используются только в частном порядке в вашем приложении), вся привязка данных к просмотру становится проще простого с CursorLoader. ИМХО, разница между созданием собственного «контент-провайдера» и реальной реализацией ContentProvider невелика, но это всего лишь мое крайне противоречивое мнение :)

3) Я знаю, что startManagingCursor/stopManagingCursor устарели, но я не ориентируюсь на Honeycomb (по крайней мере, на данный момент) и пока не хочу иметь дело с новым CursorLoader. Но в приведенном выше руководстве startManagingCursor используется везде, а stopManagingCursor никогда не вызывается ни разу. Почему нет? Android справляется с этим по-своему? В любой ситуации я должен вызвать stopManagingCursor?

Как только вы позвоните startManagingCursor(), Cursor больше не будет вашей проблемой. Android позаботится о закрытии курсора, когда ваш Activity будет уничтожен (пользователь уходит, меняет ориентацию и т. д.). Нет необходимости сопоставлять вызов startManagingCursor() с вызовом stopManagingCursor() — обычно вы не хотите снова брать на себя бремя управления Cursor после того, как избавитесь от него.

person Philipp Reichart    schedule 29.09.2011
comment
#1 Я совершенно неправильно истолковал свои мысли по этому вопросу, мне нужно перефразировать его... #2 Да, я имел в виду deactivate (опечатка). Я не могу найти никакой хорошей документации о том, как использовать LoaderManager, даже здесь, в вопросах SO. # 3 Я понимаю, но если я не должен использовать stopManagingCursor, если я сделал вызов startManagingCursor, почему этот метод вообще существует? - person rfgamaral; 30.09.2011
comment
Кроме того, только что нашел ответ на № 2; вопрос отредактирован еще раз с ответом. - person rfgamaral; 30.09.2011
comment
Только что засветился на моем сайте земного шара, сейчас читаю ваши правки. О, только что увидел: Та же сторона земного шара, просто легла спать раньше, чем ты ;) - person Philipp Reichart; 30.09.2011
comment
Ну вот, обновил мой ответ, а также несколько личных заметок о LoaderManager. - person Philipp Reichart; 30.09.2011
comment
Спасибо, очень ценю это :) Посмотрю на упомянутый учебник, возможно, в будущем я перейду на LoaderManager. - person rfgamaral; 30.09.2011
comment
LoaderManager вообще не полагается на ContentProvider... он ничего об этом не знает. Я думаю, вы хотели сказать, что CursorLoader сильно зависит от ContentProvider (поскольку метод startLoading CursorLoader содержит прямой вызов getContentResolver().query(...)). - person Alex Lockwood; 06.07.2012