New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DragSortListView.RemoveListener not working with SimpleDragSortCursorAdapter #85
Comments
Hmmm....looks like this is brought up in issue #44 (Comment: #44 (comment)). I thought there would be an easy way to handle deletes with the cursors, but it looks like once the user is done modifying the view you have to compare the cursors and then find out what was removed and also update positions for items in the database. Am I off base here, or is there an easier/different way to handle deletes? |
You are correct. The developer using DSLV has to persist the reorderings/deletions him/herself. There are several reasons for passing this responsibility onto the dslv user. 1. DSLV doesn't know when the user would like to persist the changes. 2. DSLV doesn't know how to persist the changes (b/c a Cursor is just a view into some datastore. e.g. is the Cursor from a db, a 2d array, a .csv, etc?). I should also mention that the use of remove/drop listeners with a subclass of DragSortCursorAdapter is redundant. The DragSortCursorAdapter implements the listener interfaces (which are detected when setAdapter() is called on DSLV). If you'd like additional behavior on removals or drops, you should override the remove() and drop() methods in your MAdapter class. |
Thanks, that's what I figured. As for overriding remove() and drop() in MAdapter, I think that would be like re-inventing the wheel. What I ended up doing was comparing the ListView cursor with a cursor that contained the original items from the database. The position value that is stored in the database is updated, and then the items that had been removed form the ListView are deleted from the database. There are probably better ways to go about doing this, and I realize that for large lists this could really be slow, but it works for me now. Since I wasn't able to find anything like this anywhere, I figured I'd post it here. I have a "Commit" button that basically runs an AsyncTask with the code listed below. I plan on writing up something on my blog in the next week or so too. Anyway, here's what I came up with:
Thanks again! |
This method was designed to make your life easier. For example: private class MAdapter extends SimpleDragSortListAdapter {
// ...
public void persistChanges() {
Cursor c = getCursor();
c.moveToPosition(-1);
while (c.moveToNext()) {
int listPos = getListPosition(c.getPosition());
if (listPos == DragSortListAdapter.REMOVED) {
dbAdapter.deleteItemRecord(c.getInt(c.getColumnIndex("_id")));
} else if (listPos != c.getPosition()) {
dbAdapter.updateItemPosition(c.getInt(c.getColumnIndex("_id")), listPos);
}
}
}
} |
Ahhh...that's much simpler and more efficient. However, I'm trying to implement it and I'm not having much luck. Where should persistChanges() get called from? I created the method like you have above but I'm not sure exactly where it should be called from in the code I originally posted. If I put it in getView, right before "return v;", it works, but it gets called every time anything happens to the list and bogs interaction down. I tried just overriding remove() and drop() and putting persistChanges(); in those, but that didn't work at all (list view wasn't updated and items weren't removed). I kind of figured it wouldn't work, because there's no logic to actually update the list view. I apologize for my lack of knowledge about all this, but do appreciate your help and direction. |
No problem! I would call this at the activity level. For example: public class MyActivity extends ListActivity {
// ...
@Override
protected void onPause() {
super.onPause();
mAdapter.persistChanges();
}
} |
Makes perfect sense. I think my head is about to explode though. In order to get it to work with my example I had to modify it a little. If I tried it like you have above, I got a "Cannot make a static reference to the non-static method" error. This is what worked for me:
I really appreciate all of your help with this! |
Sorry about that, I had assumed: private MAdapter mAdapter = new MAdapter(...); ;) Happy to hear it's working. |
I should have written: |
Hehe, goes both ways. ;) I should have declared that differently...correctly. For anyone that's interested in the final working code for the modified CursorDSLV demo that I hacked together, you can find it below. Remember, this is just demo code. You might want to use a button, or something else, to actually commit the changes, rather than have them automatically committed. This gives the user an "out" in case they made changes they don't want saved. To do so, you would just move the call to mMAdapter.persistChanges(); to whatever way you choose to commit the changes. public class CursorDSLV extends FragmentActivity {
private MAdapter mMAdapter;
private DatabaseAdapter mDbHelper;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.warp_main);
mDbHelper = new DatabaseAdapter(this);
mDbHelper.openConnection();
// The desired columns to be bound
String[] cols = new String[] { DatabaseAdapter.ITEM_NAME,
DatabaseAdapter.ITEM_POSITION };
// the XML defined views that the data will be bound to
int[] ids = new int[] { R.id.text, R.id.item_position_list };
// pull all items from database
Cursor cursor = mDbHelper.getAllItemRecords();
mMAdapter = new MAdapter(this, R.layout.list_item_handle_right, null,
cols, ids, 0);
DragSortListView dslv = (DragSortListView) findViewById(android.R.id.list);
// set dslv profile for faster scroll speeds
dslv.setDragScrollProfile(ssProfile);
dslv.setAdapter(mMAdapter);
mMAdapter.changeCursor(cursor);
}
private DragSortListView.DragScrollProfile ssProfile = new DragSortListView.DragScrollProfile() {
@Override
public float getSpeed(float w, long t) {
if (w > 0.8f) {
// Traverse all views in a millisecond
return ((float) mMAdapter.getCount()) / 0.001f;
} else {
return 10.0f * w;
}
}
};
private class MAdapter extends SimpleDragSortCursorAdapter {
public void persistChanges() {
Cursor c = getCursor();
c.moveToPosition(-1);
while (c.moveToNext()) {
int listPos = getListPosition(c.getPosition());
if (listPos == REMOVED) {
mDbHelper.deleteItemRecord(c.getInt(c.getColumnIndex("_id")));
} else if (listPos != c.getPosition()) {
mDbHelper.updateItemPosition(c.getInt(c.getColumnIndex("_id")), listPos);
}
}
}
public MAdapter(Context ctxt, int rmid, Cursor c, String[] cols,
int[] ids, int something) {
super(ctxt, rmid, c, cols, ids, something);
mContext = ctxt;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
return v;
}
}
@Override
protected void onPause() {
super.onPause();
mMAdapter.persistChanges();
}
@Override
public void onDestroy() {
super.onDestroy();
if (mDbHelper != null) {
mDbHelper.closeConnection();
}
}
} |
Thanks for the contribution! |
Maybe I'm missing something with this, but in trying to figure out how to get this to work with a database, I started playing around with the demo that's available. What I ended up doing is just modifying the CursorDSLV class to get it to pull info from my database. Now I'm trying to figure out how to actually remove the item from the database once it is flung away from the view. I figured that this would be accomplished by setting up a DragSortListView.RemoveListener, but when I fling to remove the item this never gets called. As you can see below, it should log some info after you remove an item, but it doesn't log anything. It correctly logs info when the profile is called though.
Am I doing something wrong or not understanding how this should be implemented?
Here's the code I'm using (yes, I purposely changed the layout to warp_main so that you could fling to remove):
The text was updated successfully, but these errors were encountered: