问题
In trying to clean up code in an existing project and remove warnings about calling showDialog()
in an Activity, I have moved a bunch of related dialogs which show up in a sequence into a new DialogFragment
class. It's working OK, however when I press the cancel button on a given dialog, it always takes me back to the previous dialog (which was saved to the back stack), whereas I want the cancel button to dismiss all of the Dialogs and go back to the View in the main activity.
Pressing the back button should continue to go back to the previous dialog on the back stack.
Here is my current code, I have simplified it to include only two dialogs, though there are several more dialogs in the chain between these two, which show up in my actual application before import()
is called.
public class ImportDialog extends DialogFragment {
private int mType = 0;
public static final int DIALOG_IMPORT_HINT = 0;
// ... several more
public static final int DIALOG_IMPORT = 8;
public interface ImportDialogListener {
public void import();
public void showImportDialog(int type);
public void dismissAllDialogFragments();
}
/**
* A set of dialogs which deal with importing a file
*
* @param dialogType An integer which specifies which of the sub-dialogs to show
*/
public static ImportDialog newInstance(int dialogType) {
ImportDialog f = new ImportDialog();
Bundle args = new Bundle();
args.putInt("dialogType", dialogType);
f.setArguments(args);
return f;
}
@Override
public AlertDialog onCreateDialog(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mType = getArguments().getInt("dialogType");
Resources res = getResources();
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
setCancelable(true);
switch (mType) {
case DIALOG_IMPORT_HINT:
// First dialog
builder.setTitle("Title");
builder.setMessage("Message");
builder.setPositiveButton(res.getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
((ImportDialogListener) getActivity()).showImportDialog(DIALOG_IMPORT_SELECT);
}
});
builder.setNegativeButton(res.getString(R.string.dialog_cancel), mNegativeClickListener);
return builder.create();
// ... several more
case DIALOG_IMPORT:
// Second dialog
builder.setTitle("Different title");
builder.setMessage("Different message");
builder.setPositiveButton(res.getString(R.string.import_message_add),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
((ImportDialogListener) getActivity()).import();
}
});
builder.setNegativeButton(res.getString(R.string.dialog_cancel), mNegativeClickListener);
builder.setCancelable(true);
return builder.create();
default:
return null;
}
}
private DialogInterface.OnClickListener mNegativeClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
((ImportDialogListener) getActivity()).dismissAllDialogFragments();
}
};
}
Then in the main Activity I implement the ImportDialogListener
interface as follows:
public void showImportDialog(int type) {
// DialogFragment.show() will take care of adding the fragment
// in a transaction. We also want to remove any currently showing
// dialog, so make our own transaction and take care of that here.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
ft.remove(prev);
}
// save transaction to the back stack (input argument is optional name) so it can be reversed
ft.addToBackStack(null);
DialogFragment newFragment = ImportDialog.newInstance(type);
newFragment.show(ft, "dialog");
}
public void import() {
// Do stuff
}
// Dismiss whatever dialog is showing... THIS IS THE PART THAT DOESN'T WORK
public void dismissAllDialogFragments() {
getSupportFragmentManager().popBackStack("dialog", FragmentManager.POP_BACK_STACK_INCLUSIVE);
Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
DialogFragment df = (DialogFragment) prev;
df.dismiss();
}
}
How can I get it to work, and am I doing something fundamentally wrong here?
回答1:
While adding a transaction to back stack, supply the name for the back stack state. e.g. dialog
Change
ft.addToBackStack(null);
to
ft.addToBackStack("dialog");
To remove entries from back stack matching a back stack state name, use FragmentManager.popBackStack. This removes all back stack states with name dialog from top until bottom of stack is reached or a back stack state entry with different name is reached. No need to explicitly call dismiss on dialog.
public void dismissAllDialogFragments() {
getSupportFragmentManager().popBackStack("dialog", FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
来源:https://stackoverflow.com/questions/25598740/how-to-dismiss-a-dialogfragment-without-going-back-to-last-item-in-stack