web-dev-qa-db-ja.com

OnCancelListenerがDialogFragmentで呼び出されていません

いくつかの項目のリストを表示する単純なAlertDialogがあり、そのうちの1つをクリックすると、クリックされた項目は囲んでいるActivityに戻されます。また、(戻るボタンを使用して)ユーザーがダイアログをキャンセルしたときにデフォルトの処理を実行したい-より具体的には、空の文字列をそのような場合の活動。

ただし、ダイアログをDialogFragmentに入れた場合(互換性パッケージから)、OnCancelListenerダイアログでダイアログを閉じると呼び出されません戻るボタン。何が悪いのですか?

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();
    }
}
22
Natix

コードからcancel()への明示的な呼び出しがないという事実に関係している可能性があります。 OnCancelListener ドキュメンテーションは言う:

これはダイアログがキャンセルされたときにのみ呼び出されます

おそらく、明示的なcancel()呼び出しが必要です。

DialogInterface#cancel() を呼び出すOnClickListenerを使用して正/負のボタンを作成するか、 OnDismissListener() を使用してリスト項目がクリックされたかどうかを確認する追加のチェック。

また、バックキーの押下をリッスンしてダイアログをキャンセルするには、 this SO answer で説明されているように、- OnKeyListener を設定できます。 =

また、ダイアログを設定したら、ユーザーがダイアログの外側をタップした場合に備えて Dialog#setCanceledOnTouchOutside() を使用することもお勧めします。

編集:以下の部分は、DialogFragmentでキャンセルイベントを処理する簡単な方法です。

DialogFragmentを使用しているため、このクラスには非常に便利なメソッド DialogFragment#onCancel() があり、DialogFragmentがキャンセルされたときに呼び出されます。そこにあなたの論理を行います。

DialogFragmentsはより複雑で、通常のダイアログとはライフサイクルがわずかに異なります。したがって、最初にドキュメントを確認して、Dialogに移植しようとしている特定のDialogFragmentベースのアプローチがあるかどうかを確認します。新しい実装が適切に機能するためのメソッドがいくつか存在する可能性があります。

46
A--C

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;
        }
    });
11
Nikhil Pingle

注:DialogFragmentはDialog.setOnCancelListenerおよびDialog.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()を削除する必要があります

10
Bao Le

実際にDialogFragmentを使用する場合、OnCancelListenerまたはOnDismissListenerを追加することはできません。DialogFragmentがこれらのメソッドへのコールバックを所有しているためです!

ここには3つのオプションがあります。

1-通常のダイアログを使用します。
2-ダイアログフラグメントをcancellable(false)に設定し、キャンセルボタンをダイアログに追加します。
3- @Nikhil Pingleの回答を確認してください。

これはDialog Fragmentのドキュメントからです

 * <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>
1