Android SimpleCursorAdapter не обновляется при изменении базы данных

43

У меня есть Android ListActivity, который поддерживается базой данных Cursor через SimpleCursorAdapter.

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

Проблема заключается в том, что когда обновленное представление выходит из экрана и перерабатывается, старое значение отображается в представлении, когда оно возвращается в представление. То же самое происходит всякий раз, когда предикат перерисовывается (изменения ориентации и т.д.).

Я использую notifydatasetchanged() для обновления адаптера курсора, но он кажется неэффективным.

Как мне обновлять базу данных, чтобы курсор также обновлялся?

Теги:
database
cursor
listactivity

6 ответов

85
Лучший ответ

Вызов requery() в Cursor при изменении данных в базе данных, которые вы хотите отразить в этом Cursor (или вещи, которые Cursor заполняет, например, ListView через CursorAdapter).

A Cursor похож на клиентский клиент ODBC - он содержит все данные, представленные результатом запроса. Следовательно, только потому, что вы меняете данные в базе данных, Cursor не будет знать об этих изменениях, если вы не обновите его с помощью requery().


ОБНОВЛЕНИЕ. Весь этот вопрос и набор ответов следует удалить из-за старости, но это, по-видимому, невозможно. Любой, кто ищет ответы на Android, должен помнить, что Android - стремительно движущаяся цель, а ответы 2009 года, как правило, хуже, чем более новые ответы.

Текущее решение состоит в том, чтобы получить свежий Cursor и использовать changeCursor() или swapCursor() на CursorAdapter, чтобы повлиять на изменение данных.

  • 0
    Так что же тогда делает notifydatachanged?
  • 12
    Там нет "notifydatachanged". Если вы имеете в виду notifyDataSetChanged () для Adapter, то именно так SimpleCursorAdapter сообщает ListView, что данные были изменены. Чтобы процитировать из документации: «Уведомляет приложенное Представление, что базовые данные были изменены, и они должны обновить себя». Однако ваша проблема не в том, что адаптер сообщает ListView об изменениях - ваша проблема в том, что адаптер не знает, что данные изменились. Вызов Requery () - это способ решить эту проблему с помощью CursorAdapter.
Показать ещё 3 комментария
36

requery теперь устарел. из документации:

Этот метод устарел. Не используйте это. Просто запросите новый курсор, чтобы вы могли сделать это асинхронно и обновить представление списка после возвращения нового курсора.

после получения нового курсора можно использовать adapter.changeCursor(cursor). это должно обновить представление.

  • 0
    Спасибо за информацию, у меня произошел сбой в Honeycomb, связанный с cursor.requery (), возможно, это за этим стоит.
  • 0
    Обычная ситуация состоит в том, чтобы изменить значение с onClickListener (). Меня озадачивает то, что, с одной стороны, мы отправляем начальный курсор через конструктор (т.е. запрос пишется вне Adpater), но с другой стороны, onlickLister определяется как вложенный класс внутри. адаптер. Таким образом, запрос нового курсора будет написан внутри класса адаптера. Это может привести к дублированию кода. Каков правильный дизайн, чтобы написать запрос только один раз в исходном коде.?
20

В случае использования загрузчика и автоматически созданного курсора вы можете вызвать:

getLoaderManager().restartLoader(0, null, this);

в вашей деятельности, сразу после изменения чего-либо в БД, для восстановления нового курсора. Не забудьте также определить обработчики событий:

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    CursorLoader cursorLoader =
            new CursorLoader(this,
                    YOUR_URI,
                    YOUR_PROJECTION, null, null, null);
    return cursorLoader;
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    adapter.swapCursor(data);
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
    adapter.swapCursor(null);
}
  • 2
    Это хорошее решение. Спасибо за этот ответ.
  • 2
    Пробовал полдюжины разных вещей из Stack Overflow, и это было то, что наконец-то сработало для меня. Спасибо!
Показать ещё 3 комментария
1

Непонятно, если вы установили свойство autoRequery для CursorAdapter в true.

Адаптер проверяет свойство autoRequery; если это false, то курсор не будет изменен.

  • 0
    protected void init (Context context, Cursor c, boolean autoRequery) Этот метод устарел. Не используйте это, используйте обычный конструктор. Это будет удалено в будущем.
0

Это легко.

private Db mDbAdapter;
private Cursor mCursor;
private SimpleCursorAdapter mCursorAd;

.....................................
//After removing the item from the DB, use this
.....................................

 mCursor = mDbAdapter.getAllItems();
 mCursorAd.swapCursor(mCursor);

Или используйте CursorLoader...

0

requery() уже устарел, просто реализуйте простой метод updateUI(), подобный этому в дочернем классе CursorAdapter, и вызовите его после обновления данных:

private void updateUI(){
    swapCursor(dbHelper.getCursor());
    notifyDataSetChanged();
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню