OnCancelListener не вызывается в DialogFragment

у меня простой AlertDialog, который отображает список некоторых элементов и при нажатии на один из них, щелкнул элемент передается обратно в вложенный Activity. Я также хочу выполнить некоторую обработку по умолчанию, когда пользователь отменяет диалог (используя назад) - более конкретно, я хочу передать пустую строку в деятельность в таком случае.

однако, если я помещу диалог в DialogFragment (от пакет совместимости), то OnCancelListener is не вызывается, когда я закрываю диалог с помощью кнопки "Назад". Что я делаю не так?

public class SelectItemDialog extends DialogFragment {

    public interface Callback {
        void onItemSelected(String string);
    }

    private static final String ARG_ITEMS = "items";

    private Callback callback;

    public static SelectItemDialog fromItems(Collection<String> items) {
        SelectItemDialog fragment = new SelectItemDialog();
        fragment.setArguments(newArguments(items));
        return fragment;
    }

    private static Bundle newArguments(Collection<String> items) {
        Bundle arguments = new Bundle();
        arguments.putStringArray(ARG_ITEMS, items.toArray(new String[items.size()]));
        return arguments;
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        callback = (Callback) activity;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final String[] items = getArguments().getStringArray(ARG_ITEMS);
        return new AlertDialog.Builder(getActivity())
            .setTitle(R.string.dialog_select_email_title)
            .setItems(items, new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    callback.onItemSelected(items[which]);
                }
            })
            .setOnCancelListener(new OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    // this code is not executed
                    callback.onItemSelected("");
                    throw new RuntimeException("dialog cancelled");
                }
            })
            .create();
    }
}

5 ответов


это может быть связано с тем, что нет явного вызова cancel() из кода. The OnCancelListener документация говорит:

это будет вызываться только при отмене диалога

который, вероятно, нуждается в явном cancel() звонок.

либо сделайте положительную / отрицательную кнопку с OnClickListener что называет DialogInterface#cancel() или использовать OnDismissListener() С дополнительной проверкой на посмотрите, щелкнул ли элемент списка.

кроме того, чтобы прослушать нажатие клавиши назад и отменить диалог, Вы можете настроить OnKeyListener, как указано в это так ответ

кроме того, как только вы настроите Диалог, было бы также неплохо использовать Dialog#setCanceledOnTouchOutside() в случае, если пользователь нажимает вне диалогового окна.

Edit: приведенная ниже Часть-это простой способ обработки событий отмены в DialogFragment.

так как вы используете DialogFragment этот класс имеет очень удобный способ, DialogFragment#onCancel(), который вызывается, когда DialogFragment отменено. Делай свою логику.

DialogFragments более сложны, с несколько иным жизненным циклом, чем обычные диалоги. Поэтому сначала проверьте документацию, если у вас есть определенный Dialogподход, который вы пытаетесь порт DialogFragment некоторые методы, которые позволит ваш новый реализация для правильной работы!


Если вы используете DialogFragment и хотите прослушать кнопку назад, а затем использовать это -

    this.getDialog().setOnKeyListener(new Dialog.OnKeyListener() {
        @Override
        public boolean onKey(DialogInterface dialog, int keyCode,
                KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                if (****) {
                    your logic
                }
                return true;
            }
            return false;
        }
    });

Примечание: DialogFragment собственный диалог.setOnCancelListener и диалог.setOnDismissListener обратных вызовов. Вы не должны устанавливать их сами.

чтобы узнать об этих событиях, переопределите onCancel(DialogInterface) и onDismiss (DialogInterface).

public class SelectItemDialog extends DialogFragment {

    @Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);
        //your code hear
        dialog.cancel();
    }
}

и вы должны удалить .setOnCancelListener()


на самом деле, если вы хотите использовать DialogFragment, вы не можете добавить OnCancelListener или OnDismissListener к нему, так как фрагмент диалога владеет обратными вызовами к этим методам!

у вас есть 3 варианта:

1-перейти с регулярными диалогами.
2-Установите фрагмент диалогового окна в cancellable (false) и добавьте кнопку Отмена в диалоговое окно.
3 - проверить @Nikhil Pingle ответ.

это из документации диалогового фрагмента

 * <p><em>Note: DialogFragment own the {@link Dialog#setOnCancelListener
 * Dialog.setOnCancelListener} and {@link Dialog#setOnDismissListener
 * Dialog.setOnDismissListener} callbacks.  You must not set them yourself.</em>
 * To find out about these events, override {@link #onCancel(DialogInterface)}
 * and {@link #onDismiss(DialogInterface)}.</p>

отменить прослушиватель или отклонить прослушиватель в DialogFragment может достичь onDismiss

            DialogFragment  newFragment = new DatePickerFragment();
            newFragment.show(getFragmentManager(), "datePicker");
            newFragment.onDismiss(new DialogInterface(){

                @Override
                public void cancel() {
                    // TODO Auto-generated method stub

                }

                @Override
                public void dismiss() {
                    // TODO Auto-generated method stub

                }

            });