質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.53%

  • Java

    13745questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Android

    6504questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

  • Kotlin

    317questions

    Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Androidのダイアログの表示時のお作法

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,578

type23

score 8

前提・実現したいこと

相談出来る方が居ないので色々とお作法を教えていだければと思います。
ストレートに言えば、サンプルに示すコードのコードレビューをして頂きたいです。

疑問点

Androidではダイアログを表示する際にAlertDialogを直接使うのではなく、DialogFragmentを介して表示するのが一般的だと解釈しました。

呼び出し元のActivity(やFragment)側でのイベントの取得が面倒になるような気がしつつ、私なりに解釈した確認ダイアログの実装が下のコードです。

自分で駄目だと思っている点

  • ダイアログを出すトリガーとなる箇所に、閉じたときのリスナーが直接書けないので可読性が悪い。
  • 複数のダイアログを出した場合は、RequestCodeを貰うなど改造して、Positive、Negativeリスナーで処理の振り分けを書かなくてはいけない。
  • 他の種類のダイアログ(アラートダイアログとか)作り、同じAcitivityで呼び出すようになると、もう収集がつかなくなりそう。
  • その他、なんとなく直感的にコードが書けない。

サンプルで作ったソースコード

public class ManyDialogActivity extends AppCompatActivity implements ConfirmDialogFragment.ConfirmDialogListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_many_dialog);

        Button button1 = (Button) findViewById(R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ConfirmDialogFragment dialog = ConfirmDialogFragment.newInstance(null, "Aを登録しますが良いですか?");
                dialog.show(getSupportFragmentManager(), "TAG");
            }
        });
        Button button2 = (Button) findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ConfirmDialogFragment dialog = ConfirmDialogFragment.newInstance(null, "Bを登録しますが良いですか?");
                dialog.show(getSupportFragmentManager(), "TAG");
            }
        });
        Button button3 = (Button) findViewById(R.id.button3);
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ConfirmDialogFragment dialog = ConfirmDialogFragment.newInstance(null, "Bを登録しますが良いですか?");
                dialog.show(getSupportFragmentManager(), "TAG");
            }
        });
    }

    @Override
    public void onClickPositive() {
        // 引数にRequestCodeのようなものを使って処理を振り分ける?
    }

    @Override
    public void onClickNegative() {
        // 引数にRequestCodeのようなものを使って処理を振り分ける?
    }
}
public class ConfirmDialogFragment extends DialogFragment {
    public static final String TITLE_KEY = ConfirmDialogFragment.class.getName() + ".TITLE_KEY";
    public static final String MESSAGE_KEY = ConfirmDialogFragment.class.getName() + ".MESSAGE_KEY";

    public static ConfirmDialogFragment newInstance(@Nullable String title, String message) {
        ConfirmDialogFragment fragment = new ConfirmDialogFragment();
        Bundle bundle = new Bundle();
        bundle.putString(TITLE_KEY, title);
        bundle.putString(MESSAGE_KEY, message);
        fragment.setArguments(bundle);
        return fragment;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Bundle arguments = getArguments();
        String title = arguments.getString(TITLE_KEY);
        String message = arguments.getString(MESSAGE_KEY);

        final Activity activity = getActivity();
        AlertDialog.Builder builder = new AlertDialog.Builder(activity)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                if (activity instanceof ConfirmDialogListener) {
                                    ((ConfirmDialogListener) activity).onClickPositive();
                                }
                            }
                        }
                )
                .setNegativeButton("キャンセル", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                if (activity instanceof ConfirmDialogListener) {
                                    ((ConfirmDialogListener) activity).onClickNegative();
                                }
                            }
                        }
                );
        return builder.create();
    }

    interface ConfirmDialogListener {
        void onClickPositive();

        void onClickNegative();
    }
}

補足情報(言語/FW/ツール等のバージョンなど)

  • Android4.4 から 7 までが一応の対象バージョンです。
  • サンプルはJavaで掲示しましたが、Kotlinで書いてます。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

■改善点
・onCreateDialogのreturnはbuilderをcreateしたものでは?

■疑問に対する回答

ダイアログを出すトリガーとなる箇所に、閉じたときのリスナーが直接書けないので可読性が悪い。

これは、リスナーをダイアログフラグメント側のフィールドに持つとダイアログフラグメントがシステムから壊された時に復帰できないので現状の実装がベターなのかなと思いますを

複数のダイアログを出した場合は、RequestCodeを貰うなど改造して、Positive、Negativeリスナーで処理の振り分けを書かなくてはいけない。

他の種類のダイアログ(アラートダイアログとか)作り、同じAcitivityで呼び出すようになると、もう収集がつかなくなりそう。
その他、なんとなく直感的にコードが書けない。

これに関してはConfirmDialogListenerの各メソッドの引数にBundleを指定することで備えるといいですね。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/31 18:04

    ありがとうございます。
    ザックリ一言で言えば、今のところこのコードでも悪くない。という認識をもちました。

    > ■改善点
    > ・onCreateDialogのreturnはbuilderをcreateしたものでは?
    失礼しました。ご指摘の通りです。動かしてから貼り付けるべきでした。

    > これに関してはConfirmDialogListenerの各メソッドの引数にBundleを指定することで備えるといいですね。
    パっと具体的なコードが思いつかなかったのですが、どのような感じでしょうか?

    ご指摘のイメージから実験コードを書いた方が話が進みやすいかと思いましたが、ちょっと手間取りそうだったので、急ぎ聞かせていただきました。

    キャンセル

  • 2017/03/31 18:43

    Activityで画面遷移する時にBundleにいろいろなデータを入れてやりとりしますよね?
    あれと同じことをコールバックインターフェースで行うと、ダイアログクラスが増えてもコールバックインターフェースは1つで済みます。
    Bundleに入れる値もしっかりと設計すればある程度保守性は保てるかなと思います。

    キャンセル

  • 2017/04/03 10:53

    遅くなりました。ありがとうございます。
    週末バタバタしてしまい、全く実験が出来なかったです。

    > Bundleに入れる値もしっかりと設計すればある程度保守性は保てるかなと思います
    なるほど。やはりこの辺りはしっかり腰を据えてやらないと難しそうですね。
    結局ダイアログを閉じたときにViewをゴニョゴニョしたいことも多く、activity間の結合を疎にしたいと思ったときに、行き当たりばったりだと期待した動きにならず、無駄に労力を費やしてました。

    キャンセル

+1

Androidは魔境です。
DialogFragmentってあくまでダイアログ風なFragmentなんですよね。。
まぁ使いづらいのでAlertDialogと同じ事できるクラスは用意しておくとある程度楽ですが

コールバック周りはputSerializableとかで上で言うとnewInstance時にリスナー入れたりも一応できますが、回転とか考えると現状のやり方が私はいいかと。
あと個人的にはonAttachでリスナーセットされてるか処理します。

あまりにもリスナー多い場合はidなんか用意したりBundleとうまく向き合います。
なんかActivityResultやBroadCastに慣れるとimplementsが増えるくらい気にしなくなる。。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/31 18:21

    ありがとうございます。
    サンプルばかり読んでいて、実際のアプリのコードを読んだことがないので、どれだけ皆さんが苦しんでいるかが分からなかったです。

    > Androidは魔境です。
    割りとこの一言で救われた気がします。
    たかがダイアログを表示して、処理を振り分けるのにここまで苦労するとは思いませんでした。
    正直30分もあれば実装できると思ってたのですが、1日がかりです。
    みなさんこんなもんなんですか?

    > コールバック周りはputSerializableとかで上で言うとnewInstance時にリスナー入れたりも一応できますが
    この手法を最初に考えついたのですが、私の設計が悪いのか、関連する全てのクラスをSerializableにしないといけなくなり、Serializableである必要のないクラスまでSerializableにしなくてはならなくなってしまいました。

    > あと個人的にはonAttachでリスナーセットされてるか処理します。
    後学のためにこちらの理由を教えて頂けますか?

    > あまりにもリスナー多い場合はidなんか用意したりBundleとうまく向き合います。
    Bundleについての理解が浅いようです。
    先の方にもBundleに関してアドバイスを頂きましたが、理解が出来なかったです。
    私がもう少し知見を深めなくては話が進まないですね。。。

    キャンセル

  • 2017/03/31 18:30

    うーん、とりあえずこちらの端末で動いたけどあっちで動かないとか普通にあるのでまず個人的には安定して動くような方法を重視していますね。ユーザーがどんな操作するか分からないので。。あとSupportLibraryとか更新するだけで落ちたりする場合もあるし。。。

    onAttachでリスナーセットは
    結局リスナーつけると言う事は返すと言う事なのでコールバックできないと意味ないので。最初についてるか判断してなければなければな処理をしますね。まーあまりないですが例えば不正な呼び出しですよとか。

    試してはいませんがこちらの方がソース上げてるみたいですねputSerializable
    https://gist.github.com/mstssk/7123411

    キャンセル

  • 2017/04/03 11:01

    遅くなりました。ありがとうございます。

    > まーあまりないですが例えば不正な呼び出しですよとか。
    今はリスナーをセットしなければ何もしない。という動きにしたかったので、現状のままでも大丈夫そうですね。

    参考にあげて頂いたコードも見ました。
    最初に思いついた手法でしたが、理解が浅いせいか期待の動きをしなかったので、今の手法を取り入れました。

    コードをスッキリさせるためにKotlinで書き始めましたが、動くコードを書くうちに混沌としてきてしましました。。
    Androidで製品を作る。というのは想像以上にコストが高いですね。

    キャンセル

  • 2017/04/03 11:17

    onAttachについてはライフサイクル的にもActivityに取り付けられた時なのでって意味でやってるとこもありますね。
    特別なことすると大変な時もありますが慣れてくればクセもわかってくると思いますよ。

    キャンセル

  • 2017/04/04 11:12

    ありがとうございます。
    なるほど、恐らく誤解してました。
    上手く説明が出来ないですが、確かにonAttachでチェックする方が良さそうな気がしてきました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.53%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Java

    13745questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Android

    6504questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

  • Kotlin

    317questions

    Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。