0

I have an implementation of CursorAdapter which I am using with a Loader through a ListFragment. This works fine except for the problem below. It contains the following code. Each row contains a checkbox where the user can select the items. There is a delete button on actionbar that allows the user to delete the selected items. This happens through my implementation of 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
        }

}

Here is the corresponding function in the 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;
}

When I select multiple items and delete, the first time it works fine and does what it is supposed to do. However, now if I select some more item or items, and again click on delete, it fails at line XX.

The error I get in LogCat is java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteQuery: SELECT id as _id, name, value FROM stufftable WHERE (value=?). The line at which it fails is: cursor.moveToPosition(checkedItemKey)

I did look at this, and understand that somehow I am leaving the cursor in a closed or an inconsistent state. However, I am not able to think of anything that could solve my issue. What am I doing wrong?

Note: I am calling getContext().getContentResolver().notifyChange(uri, null) in my ContentProvider.delete() which along with the Loader, I thought, would notify the cursor. Also I tried putting this.notifyDataSetChanged() at the end without any luck.

Community
  • 1
  • 1
rgamber
  • 5,749
  • 10
  • 55
  • 99

2 Answers2

0

Create a new Cursor in deleteStuff() every time you enter and not use the one from newView, that searches for the entry you want to delete. (this should work)

You could also try using the cursor from bindView but I am not sure if this will work.

Dan Cuc
  • 76
  • 4
  • I think this is not a good idea. The point of using a `CursorAdapter` with a `Loader/LoaderManager` is that I don't have to manage the cursor myself :) – rgamber Mar 05 '14 at 17:46
  • It's meant for loading, you could also try cursor.requery() at the end of deleteStuff(), but this method seems to be deprecated. Let me know if you tried it and if it works. In the mean time I will think of a better way. – Dan Cuc Mar 06 '14 at 07:14
  • You could also try using the cursor from bindView(View view, Context context, Cursor cursor). I think bindView uses a refreshed cursor. – Dan Cuc Mar 06 '14 at 08:01
  • Thanks for the input. Yes, I found a better way and will post it as the correct answer shortly! – rgamber Mar 06 '14 at 20:53
0

Update: I finally did this in a much simpler way. I was populating checkedItems with the position inside the CheckBox.setOnCheckedChangeListener() which is inside the bindView(). I changed this to contain the the id of the item being deleted instead of getting the position, and then using the cursor with position :). So in the delete() I already have the Ids ready to be deleted, and I do not have to mess with the cursor here. This works as I desire. I wish I had thought of this sooner, then I wouldn't have had to post the question here. I hope this helps someone!

rgamber
  • 5,749
  • 10
  • 55
  • 99