You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Apr 26, 2023. It is now read-only.
Repository navigation
This repository was archived by the owner on Apr 26, 2023. It is now read-only.
When using a cursor adapter with EnhancedListView after I swipe to dismiss the swiped view reappears momentarily and then disappears creating a very ugly flickering effect.
After looking on StackOverflow it looks this is a known issue with CursorAdapters and animated list views such as EnhancedListView. The issue seems to be that the animation finishes and redraws the list view before the item is actually deleted from the adapter. This causes the item being swiped out to reappear on the list and latter when the CursorAdapter finishes updating with the item removed the list is again redrawn without the removed item. This results in noticeable flickering.
I tried several solutions proposed (see links below) but they did not work with the EnhancedListView. The last solution I tried was to reload the cursor without the deleted item inside the dismiss callback but the flickering is still there.
I got a simple (and ugly) work around to the issue. In the onDismiss callback I create a new cursor with the list data but that excludes the item being deleted:
public Undoable onDismiss(EnhancedListView list, int pos) {
long id = mAdapter.getItemId(pos);
String selection = "_id <> " + id;
mTempCursor = getContentResolver(URI, COLUMNS, selection. ....);
mAdapter.swapCursor(mTempCursor);
// after this then proceed to delete the item from the db
getContentResolver().delete(.....);
}
Make sure to close the cursor when we get the real cursor with the item already deleted
Loading the cursor on the onDismiss callback may beat the purpose of using a loader in the first place and may potentially present a performance issue. If performance is an issue for you then using the ProxyCursor approach (see links on previous comment) may be better. This if you are willing to write and override all methods needed to implement the proxy cursor class.
Still I am thinking about good workaround solutions. If I find some free time I will dig a bit into the CursorAdapter and perhaps I will find a solution to add a wrapper (or something similar) to the library, that blocks until deletion has finished.
Hi, I solved it by creating my own adapter which extends BaseAdapter and it has two private members List and Stack. List contains elements provided by given Cursor and Stack excluded elements. So, when you want to delete ClassA from list, you just push it on stack, remove from list and call notifyDataSetChanged(), and when you want to do undo, you just pull it from stack ,put it in list again in its old position and call notifyDataSetChanged() again. You really delete those object in onLoaderReset() by deliberetly calling doRealDelete() in your adapter, which pulls elements from stack one by one and do bulk delete through your ContentProvider class. You obviuosly won't delete them one by one... This approach probably has its flaws but it is doing well in my app.
Another solution could be to convert your cursor adapter to an ArrayList adapter or Base adapter. When onLoadFinished is called, move all cursor items into your ListView adapter. In this way you solve the problem. But as all of other ways, there could be performance issues, because first you have to iterate all cursor items, pass them to the list adapter which will iterate again through all of them. I think this is the simpliest solution but in my case would result in a huge code review.
I decided to go for an ArrayAdapter. I'm using 20 records in the worst case, so performances wouldn't be a problem. Please keep me updated if you find better solutions
Finally I moved to ArrayAdapter in onLoadFinished usage as edoardotognoni already told. I believe there could be a performance issue, but it works in my concrete case. Not a solution but workaround of course.
@timroes maybe a workaround would be to introduce a small delay after the collapse animation. Let's say a method like setDelayAfterCollapse(int delayInMiliseconds). This way the collapse animation would be followed by this delay and adapter would have time to swap the Cursor.
I've made an implementation of base cursor adapter class that can be used as workaround for this problem: https://gist.github.com/q1p/0b95633ab9367fb86785
Still not perfect solution, but technically more efficient then listed above and on StackOverflow. It's based on HashSet and default item id (getItemId()), so performance should not be an issue, as contains() method has O(1) time complexity and actually set will contain zero or one item most of the time.
Also it's depends on Guava. If you are not using Guava, just replace set construction on line 91.
To use it in your project you can just extend this class instead of CursorAdapter and add few lines of code in onDismiss():
@Override
public EnhancedListView.Undoable onDismiss(EnhancedListView enhancedListView, int i) {
adapter.putPendingDismiss(id);
adapter.notifyDataSetChanged();
...
}
This solution will not work if you're using list dividers (because this adapter displays empty view instead of dismissed item). You should add margins in your item layout to make spacing between items and include divider in item layout.
Activity
hsanson commentedon Oct 2, 2013
I got a simple (and ugly) work around to the issue. In the onDismiss callback I create a new cursor with the list data but that excludes the item being deleted:
Make sure to close the cursor when we get the real cursor with the item already deleted
Loading the cursor on the onDismiss callback may beat the purpose of using a loader in the first place and may potentially present a performance issue. If performance is an issue for you then using the ProxyCursor approach (see links on previous comment) may be better. This if you are willing to write and override all methods needed to implement the proxy cursor class.
timroes commentedon Oct 2, 2013
Thanks for your report. As you mentioned the swapping adapters might not be the finest solution.
I explained here why I cannot fix this issue.
Still I am thinking about good workaround solutions. If I find some free time I will dig a bit into the
CursorAdapterand perhaps I will find a solution to add a wrapper (or something similar) to the library, that blocks until deletion has finished.edoardotognoni commentedon Mar 25, 2014
Hi guys. Same problem here. Did you find a workaround for that?
draskosaric commentedon Mar 25, 2014
Hi, I solved it by creating my own adapter which extends BaseAdapter and it has two private members
ListandStack. List contains elements provided by given Cursor and Stack excluded elements. So, when you want to delete ClassA from list, you just push it on stack, remove from list and callnotifyDataSetChanged(), and when you want to do undo, you just pull it from stack ,put it in list again in its old position and call notifyDataSetChanged() again. You really delete those object inonLoaderReset()by deliberetly callingdoRealDelete()in your adapter, which pulls elements from stack one by one and do bulk delete through yourContentProviderclass. You obviuosly won't delete them one by one... This approach probably has its flaws but it is doing well in my app.edoardotognoni commentedon Mar 26, 2014
Another solution could be to convert your cursor adapter to an ArrayList adapter or Base adapter. When onLoadFinished is called, move all cursor items into your ListView adapter. In this way you solve the problem. But as all of other ways, there could be performance issues, because first you have to iterate all cursor items, pass them to the list adapter which will iterate again through all of them. I think this is the simpliest solution but in my case would result in a huge code review.
draskosaric commentedon Mar 26, 2014
If you find better solution, please post it here, since I am looking for better solution myself.
edoardotognoni commentedon Mar 26, 2014
I decided to go for an ArrayAdapter. I'm using 20 records in the worst case, so performances wouldn't be a problem. Please keep me updated if you find better solutions
Darclight commentedon Apr 2, 2014
Did anyone find a better solution for this issue?
Yougin commentedon Apr 18, 2014
Finally I moved to ArrayAdapter in onLoadFinished usage as edoardotognoni already told. I believe there could be a performance issue, but it works in my concrete case. Not a solution but workaround of course.
micHar commentedon Apr 30, 2014
@timroes maybe a workaround would be to introduce a small delay after the collapse animation. Let's say a method like setDelayAfterCollapse(int delayInMiliseconds). This way the collapse animation would be followed by this delay and adapter would have time to swap the Cursor.
v3nko commentedon May 5, 2014
I've made an implementation of base cursor adapter class that can be used as workaround for this problem: https://gist.github.com/q1p/0b95633ab9367fb86785
Still not perfect solution, but technically more efficient then listed above and on StackOverflow. It's based on HashSet and default item id (getItemId()), so performance should not be an issue, as contains() method has O(1) time complexity and actually set will contain zero or one item most of the time.
Also it's depends on Guava. If you are not using Guava, just replace set construction on line 91.
To use it in your project you can just extend this class instead of CursorAdapter and add few lines of code in onDismiss():
This solution will not work if you're using list dividers (because this adapter displays empty view instead of dismissed item). You should add margins in your item layout to make spacing between items and include divider in item layout.
Have a nice swiping.
malinkang commentedon Jul 12, 2014
i meet the same problem
m2kk commentedon Nov 18, 2014
for me this worked:
http://stackoverflow.com/a/25202243/371749