CursorAdapter backed ListView delete animation "flickers" on delete
android, android-animation, android-listview
Solution
I know this question has been tagged as "answered" but as I pointed out in the comments, the problem with using a MatrixCursor is that it's too inefficient. Copying all the rows except for the row to be deleted means that row deletion runs in linear time (linear in the number of items in the listview). For large data and slower phones, that's probably unacceptable.
An alternate approach is to implement your own AbstractCursor that ignores the row to be deleted. This results in the fake row deletion running in constant time and with negligible performance penalty when drawing.
A sample implementation:
public class CursorWithDelete extends AbstractCursor {
private Cursor cursor;
private int posToIgnore;
public CursorWithDelete(Cursor cursor, int posToRemove)
{
this.cursor = cursor;
this.posToIgnore = posToRemove;
}
@Override
public boolean onMove(int oldPosition, int newPosition)
{
if (newPosition < posToIgnore)
{
cursor.moveToPosition(newPosition);
}
else
{
cursor.moveToPosition(newPosition+1);
}
return true;
}
@Override
public int getCount()
{
return cursor.getCount() - 1;
}
@Override
public String[] getColumnNames()
{
return cursor.getColumnNames();
}
//etc.
//make sure to override all methods in AbstractCursor appropriately
Follow all the steps as before except:
- In SwipeDismissList.OnDismissCallback.onDismiss(), create new CursorWithDelete.
- swap over the new cursor
Problem
I'm trying to implement swipe to delete and in a `ListView` using the SwipeToDismissUndoList library which extends Roman Nurik's SwipeToDismiss sample. My issue is in the delete animation. Since the `ListView` is backed by a `CursorAdapter`, the animation triggers the `onDismiss` callback in `onAnimationEnd` but this means that the animation has run and reset itself before the `CursorAdapter` updates with the delete. This ends up looking like a flicker to the user where they delete a note by swiping it away, then the view is back for a split second and then disappears because the `CursorAdapter` has picked up the data change. Here is my `OnDismissCallback`: ``` private SwipeDismissList.OnDismissCallback dismissCallback = new SwipeDismissList.OnDismissCallback() { @Override public SwipeDismissList.Undoable onDismiss(ListView listView, final int position) { Cursor c = mAdapter.getCursor(); c.moveToPosition(position); final int id = c.getInt(Query._ID); final Item item = Item.findById(getActivity(), id); if (Log.LOGV) Log.v("Deleting item: " + item); final ContentResolver cr = getActivity().getContentResolver(); cr.delete(Items.buildItemUri(id), null, null); mAdapter.notifyDataSetChanged(); return new SwipeDismissList.Undoable() { public void undo() { if (Log.LOGV) Log.v("Restoring Item: " + item); ContentValues cv = new ContentValues(); cv.put(Items._ID, item.getId()); cv.put(Items.ITEM_CONTENT, item.getContent()); cr.insert(Items.CONTENT_URI, cv); } }; } }; ```