2019-03-15Androidの公式ドキュメントよりダイアログの表示サンプルを試してみた。ドキュメントではJavaで記述されているがここではKotlinに書き直して実装した。本プロジェクトはGithubリポジトリへ公開してある。ダイアログの基本Androidでダイアログを表示させるにはDialogクラスを継承したAlertDialogを使う。Activityでインスタンス生成するのではなく、DialogFragmentクラスを経由してインスタンスを生成する。DialogFragmentクラスはFragmentを継承しているのでActivityのライフサイクルと同期することができる。DialogFragmentでカプセル化されるのでActivityが肥大化せず、ダイアログを管理しやすくなる。実際にサンプルを見たほうが分かりやすいので、次ではCancelとDoneの2つのボタンを実装したシンプルなダイアログを作っていく。シンプルなダイアログDialogFragmentクラスを継承したSimpleDialogFragmentクラスを作成する。onCreateDialogメソッドをオーバーライドしてその中でAlertDialogのインスタンスをビルダーで生成している。Activityからは次のようにして呼び出すことができる。以降、ダイアログの呼び出しはすべてこの方法で行う。リストメニューのダイアログ先程のシンプルなダイアログではsetPositiveButtonなどでボタンを追加したが、リスト表示ではsetItemsメソッドを使って配列をセットする。ここではsetMessageを実装してしまうとリストが表示されなくなるので注意したい。setItemsメソッドの第二引数へはクリックされたときの処理をラムダ式を渡すことになっている。このラムダ式はOnClickListenerインタフェースで定義されている。ラムダ式内の第二引数(which)にはクリックされた配列のインデックスが渡される。チェックボックスのダイアログチェックボックスタイプのダイアログにはsetMultiChoiceItemsを使う。setMultiChoiceItemsの第二引数には、予めチェックしておきたい場所をbooleanArray型で渡すことができる。ラジオボタンのダイアログラジオボタンタイプのダイアログではsetSingleChoiceItemsを使う。setSingleChoiceItemsの第二引数にデフォルトでチェックしておきたいインデックスをint型で渡すことができる。カスタムレイアウトのダイアログ(ログイン入力)ダイアログのレイアウトを自由にカスタマイズすることができる。ここでは公式ドキュメントにならってログイン入力用のダイアログを実装した。表示したいレイアウトファイルdialog_signin.xmlを次のように作成する。このレイアウトをDialogFragmentクラス内でinflaterでinflateする。dialog_signinレイアウトを元にしたViewを生成する。丁寧にプログラムを追えば何も難しいことはない。ダイアログからアクティビティへコールバックする最後にアクティビティへコールバック可能なダイアログを作成する。インタフェースを使ってコールバックを実装することでActivityとダイアログを疎結合にすることができ、キレイなコードで管理することができる。ここではシンプルなダイアログのプログラムを元に改造した。上記のプログラムを詳しく見ていこう。コールバック用のインターフェースNoticeDialogListerを、DialogFragmentを継承したNoticeDialogFragmentクラス内に作成する。このインタフェースはダイアログを呼び出すホストつまりMainActivityへ実装することになる。onAttachでMainActivity(ここではContextになっているが)をNoticeDialogListerへキャストしている。ホストのActivityにNoticeDialogListerインタフェースが実装されていなければ例外がスローされるようになっている。このことで実装のし忘れを避けることができるのだ。ダイアログのボタンクリックイベント内でNoticeDialogListerのメソッドを実行しているのがわかるだろう。このコールバックの実装パターンは、iOS開発では頻繁に行われるデリゲートでのコールバックとよく似ている。Objective-C/SwiftのprotocolがJava/Kotlinのinterfaceに対応しているのだ。iOSでは強参照を避けるためにweakを指定するが、AndroidでのFragmentを通した実装ではその必要がないようである。ここは確かなことは言えないのだが、ダイアログを終了するとDialogFragmentのonDestroyとonDetachが呼ばれることを確認しているので問題ないということにしたい。Dialogueの語源はlog(話す)から来ている。logはギリシャ語で「話す」や「単語」「会話」を意味する。playと書かれているように、本やゲームにおいての書かれた対話となる。houseというように木という意味もある。文字を木に書いていた歴史からもlogが対話(書かれた)などの意味をもつのは自然なことではないだろうか。dialogue.ちなみにlogを語源とする単語は他にもたくさん存在する。monologue(独白)アプリのDialogもユーザーとの対話ということなので、一方的なスパムアラートにならないように表示のやり方には十分気を配りたいところである。