Looking for suggestions on how to reuse AlertDialogs to confirm actions of contextual menus on the items of an ActivityList
- by Ozone
I use a ListActivity to display a list of items. The user can long-press an item in the list to display a contextual menu. This menu contains among other things an option to delete the long-pressed item. When the user selects this option, a dialog pops up asking for confirmation of the deletion. Upon confirmation, the item is deleted from the list.
I would like to reuse the AlertDialog as much as possible. My attempts at using onPrepareDialog(int, View, Bundle) have been defeated by the fact that the Bundle is not passed to the DialogInterface.OnClickListener. I end up having to recreate a listener on every invocation.
I see several ways to solve this:
recreate the dialog on every occasion (pros: simple, cons: wasteful)
keep the DialogInterface.OnClickListener in a field on the ListActivity and keep the item to be deleted as a field of the listener. (pros: no memory waste, cons: need to manage state). Q: is this safe?
have onPrepareDialog update the title, and bind new View.OnClickListeners on the buttons of the AlertDialog. (pros: limit waste, cons: new View.OnClickListener on every invocation).
If DialogInterface.OnClickListener accepted a Bundle, I wouldn't have to jump through hoops to keep track of the item being deleted.
This is not a blocker, but I would love to see an elegant solution. I would love to hear your suggestions :)
Here is the code for option #1, if you want to play with this:
public class Example extends ListActivity {
private static final int CONFIRM_DELETE_DIALOG = 1;
private static final String POSITION_KEY = "position";
private ArrayAdapter<String> mAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAdapter = new ArrayAdapter<String>(
this, android.R.layout.simple_list_item_1,
new String[] { "one", "two" });
setListAdapter(mAdapter);
registerForContextMenu(getListView());
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
getMenuInflater().inflate(R.menu.my_lovely_menu, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
case R.id.delete_item:
Bundle bundle = new Bundle();
bundle.putInt(POSITION_KEY, info.position);
showDialog(CONFIRM_DELETE_DIALOG, bundle);
return true;
default:
return super.onContextItemSelected(item);
}
}
@Override
protected Dialog onCreateDialog(int id, Bundle args) {
switch (id) {
case CONFIRM_DELETE_DIALOG:
final int position = args.getInt(POSITION_KEY);
AlertDialog.Builder builder = new AlertDialog.Builder();
builder.setCancelable(false);
builder.setTitle(String.format(
getString(R.string.confirm_delete), mAdapter.getItem(position)));
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
mAdapter.remove(mAdapter.getItem(position));
// Dismiss the dialog to ensure OnDismissListeners are notified.
dialog.dismiss();
break;
case DialogInterface.BUTTON_NEGATIVE:
// Cancel the dialog to ensure OnCancelListeners are notified.
dialog.cancel();
break;
}
// Remove the dialog so it is re-created next time it is required.
removeDialog(CONFIRM_DELETE_DIALOG);
}
};
builder.setPositiveButton(android.R.string.yes, listener);
builder.setNegativeButton(android.R.string.no, listener);
return builder.create();
default:
return super.onCreateDialog(id, args);
}
}
}