Обновление курсора в фоновом потоке - PullRequest
1 голос
/ 15 ноября 2011

У меня проблема, аналогичная описанной в этом обсуждении : мне нужно обновить ListView при изменении базовой базы данных, но запрос дорогой, поэтому я делаю это в AsyncTask.

Вот что я делаю, когда обновленный Курсор готов. (Это также, как список изначально заполняется при запуске.)

@Override
protected void onPostExecute(Cursor result) {
    if (activity != null) {
        if (currentCursor != null) {
            // existing cursor is closed by adapter.changeCursor() so
            // we don't need to explicitly close it here 
            stopManagingCursor(currentCursor);
        }
        currentCursor = result;
        startManagingCursor(currentCursor);

        if (adapter == null) {
            adapter = getAdapter(result);
            setListAdapter(adapter);
        } else {
            adapter.changeCursor(result);
        }

        activity.onGotList(result, dbAdapter);
    }
}

Вот ошибка, которую я получаю. Это происходит не каждый раз, что еще более расстраивает.

Releasing statement in a finalizer. Please ensure that you explicitly call close() on your cursor: SELECT DISTINCT   t._id AS _id,   t.amount,   t.date,   t.memo,   t.synced,   t.flag,   (children.pa
android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
     at android.database.sqlite.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:62)
     at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:100)
     at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:46)
     at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:53)
     at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1412)
     at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1382)

Итак, я явно не правильно закрываю курсор. Если я вызываю currentCursor.close() вместо того, чтобы полагаться на закрытие исходящего Курсора на adapter.changeCursor(), то я получаю предупреждения о двойном закрытии Курсора или закрытии Курсора null.

Как правильно это сделать?

В обсуждении, на которое я ссылался, Дайан Хэкборн предлагает вместо него использовать Loader. Это не вариант для меня, так как мой код должен работать на Android 2.1.

Ответы [ 3 ]

0 голосов
/ 15 ноября 2011

В принципе, это возможно, но очень плохая практика - обращаться к одной и той же базе данных от двух разных помощников, поэтому, если у вас есть действие, выполняющее запросы к базе данных, у вас также не должно быть потока, обращающегося к нему, в противном случае android выдаст тихийошибка в logcat, а затем забыть о запросе ...

Лучшее решение, которое я нашел, это реализовать пул потоков runnables, каждый из которых является запросом к базе данных, и все они используют один и тот же помощник по базе данных.Следовательно, только один поток обращается к базе данных одновременно, и база данных просто открывается и закрывается, когда пул потоков запускается / останавливается.

Реализация шаблона пула потоков может быть найдена здесь: http://mindtherobot.com/blog/159/android-guts-intro-to-loopers-and-handlers/

0 голосов
/ 15 ноября 2011

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

что-то вроде

adapter.getCursor().requery();

, хотя, если вы находитесь в потоке, отличном от основного потока пользовательского интерфейса, вы можете вызвать егос

//Did not realize this was deprecated Thanks to Graham Borland for the heads up
runOnUiThread(new Runnable(){
    public void run(){
        adapter.getCursor().requery();
    }
});

В зависимости от вашей настройки.

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

stopManagingCursor(adapter.getCursor());
if (!adapter.getCursor().isClosed()) 
    adapter.getCursor().close();
//cursor creation stuff here if needed
startManagingCursor(newCursor);
adapter.changeCursor(newCursor);
0 голосов
/ 15 ноября 2011

Попробуйте .close () курсор, когда действие приостановлено или завершено. В разделе действия onPause () или onDestroy ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...