Удаление элементов в CursorAdapter

У меня есть реализация CursorAdapter, которую я использую с Loader через ListFragment. Это отлично работает, за исключением проблемы ниже. Он содержит следующий код. Каждая строка содержит флажок, в котором пользователь может выбирать элементы. На панели действий есть кнопка удалить, которая позволяет пользователю удалить выбранные элементы. Это происходит благодаря моей реализации ContentProvider.

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    //some logic
    this.cursor = cursor; //class variable assignment
}

void deleteStuff() {

        if (cursor == null) {
            return;
        }

        if (checkedItems == null || checkedItems.size()==0) { //A Sparse boolean array which saves the positions of items the user selected
            return;
        }

        final SparseIntArray checkedKeys = new SparseIntArray();  //positions of selected items
        final SparseLongArray checkedIds = new SparseLongArray(); //ids of the items at the resp keys

        for (int i = 0; i < checkedItems.size(); i++) {
            final int checkedItemKey = checkedItems.keyAt(i);
            checkedKeys.append(i, checkedItemKey);
            cursor.moveToPosition(checkedItemKey); //the line at which it fails!!!!!!!!
            checkedItemIds.append(checkedItemKey, Long.parseLong(c.getString(0)));
        }

        for (int i = 0; i < checkedItems.size(); i++) {
            myContentProvider.delete(uri, selection, args); //not putting the code for these 3 variables as not required
        }

}

Вот соответствующая функция в ContentProvider:

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    int uriType = sURIMatcher.match(uri);
    SQLiteDatabase sqlDB = sqlitehelper.getWritableDatabase();
    int rowsDeleted = sqlDB.delete(TJItemTable.TABLE_NAME, selection, selectionArgs);
    getContext().getContentResolver().notifyChange(uri, null);
    return rowsDeleted;
}

Когда я выбираю несколько элементов и удаляю их, в первый раз он работает нормально и делает то, что должен делать. Однако теперь, если я выберу еще один или несколько элементов и снова нажму «Удалить», произойдет сбой в строке XX.

Ошибка, которую я получаю в LogCat: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteQuery: SELECT id as _id, name, value FROM stufftable WHERE (value=?). Строка, в которой он терпит неудачу: cursor.moveToPosition(checkedItemKey)

Я просмотрел это, и понимаю, что каким-то образом я оставляю курсор в закрытом или несогласованном состоянии. Однако я не могу придумать ничего, что могло бы решить мою проблему. Что я делаю неправильно?

Примечание. Я вызываю getContext().getContentResolver().notifyChange(uri, null) в своем ContentProvider.delete(), что, как я думал, вместе с Loader будет уведомлять курсор. Также я безуспешно пытался поставить this.notifyDataSetChanged() в конце.


person rgamber    schedule 05.03.2014    source источник
comment
опубликуйте logcat и завершите ContentProvider   -  person pskink    schedule 05.03.2014


Ответы (2)


Создавайте новый курсор в deleteStuff() каждый раз, когда вы вводите и не используйте тот из newView, который ищет запись, которую вы хотите удалить. (это должно работать)

Вы также можете попробовать использовать курсор из bindView, но я не уверен, что это сработает.

person Dan Cuc    schedule 05.03.2014
comment
Я думаю, что это не очень хорошая идея. Смысл использования CursorAdapter с Loader/LoaderManager в том, что мне не нужно самому управлять курсором :) - person rgamber; 05.03.2014
comment
Он предназначен для загрузки, вы также можете попробовать cursor.requery() в конце deleteStuff(), но этот метод кажется устаревшим. Дайте мне знать, если вы пробовали это, и если это работает. В то же время я буду думать о лучшем пути. - person Dan Cuc; 06.03.2014
comment
Вы также можете попробовать использовать курсор из bindView (представление просмотра, контекст контекста, курсор курсора). Я думаю, что bindView использует обновленный курсор. - person Dan Cuc; 06.03.2014
comment
Спасибо за отзыв. Да, я нашел лучший способ и вскоре опубликую его как правильный ответ! - person rgamber; 07.03.2014

Обновление: наконец-то я сделал это намного проще. Я заполнял checkedItems позицией внутри CheckBox.setOnCheckedChangeListener(), которая находится внутри bindView(). Я изменил это, чтобы содержать идентификатор удаляемого элемента вместо получения позиции, а затем использовать курсор с позицией :). Итак, в delete() у меня уже есть идентификаторы, готовые к удалению, и мне не нужно возиться с курсором здесь. Это работает так, как я хочу. Жаль, что я не подумал об этом раньше, тогда мне не пришлось бы размещать вопрос здесь. Я надеюсь, что это помогает кому-то!

person rgamber    schedule 16.03.2014