ためしにDialogFragmentを使いやすくするようなラッパーを作ってみました。

 DialogFragmentの基本的な動作についてはこちらから。
 DialogFragmentでは、ただそれを継承したクラスのプロパティに設定したい項目を設定しても、スマホを縦横に動かしたときに再生成されて消えてしまう。そのため少なくともonCreate時にデータを渡してあげないと行けないという面倒なことがあるというのが基本的な動作のおさらい。
 またDialogFragmentではコンストラクタに引数を設定できない仕様になっているので、コンストラクタで引数を渡すことができない。なのでBuilderパターンを利用してインスタンスを生成し、そこの引数で処理を振り分ける必要がある。
 このように普通にプロパティを設定してデータを受け渡すだけではスマホを縦横移動させた時にメンバ変数が消えてしまう。強引な解決方法としては、DialogFragmentを継承したクラスにcompanion objectを設定して、いわゆるstatic変数を設定することだが、これだと同じクラスを複数で使うときに同じ挙動になってしまうので意味がないので、static変数を使うのはあまりいい方法ではない。
 なら新しいクラスを作り、そこに設定させる情報を集約してBundleを利用して渡してしまえばいいのでは?ということで参考に作成してみたのが以下のソース。

 詳しい流れはこのような感じ。
 TestDialogクラスはDialogFragmentを継承しているクラスなので、このクラスのonCreateDialogメソッドでAlertDialogを生成すればいろいろな問題を勝手に解決してくれる。
 TestDialogには内部クラスDataStoreがあり、このクラスにAlertDialogで設定する内容を保存してTestDialogに戻してあげることで設定した内容を反映してくれる。このDataStoreクラスはBundleで渡されるのでスマホの縦横移動時にも対応してくれる。

 具体的な使用方法はこのような感じ。
 TestDialog.DataSore()はcompanion objectなのでこれを呼び出すとDataStoreクラスのインスタンスを生成してくれる。そのインスタンスにはAlertDialogの設定に関する設定内容やコールバックなどが含まれているのでそれを設定してあげる。
 最後にTestDialog.Builder()をして引数に前述のDataStoreのインスタンスを渡してあげることでDataStoreに設定した内容に従ってダイアログを生成してくれる。
 ここで設定できる内容はごく一部だが、下記のようにメソッドを拡張することで、より使い安いダイアログが作成できる。

 なおAlertDialogにカスタムレイアウトを適用したいと思うけど、そのカスタムレイアウトのイベントを取得する方法がDialogFragmentにはない。そのため、ありかじめレイアウトのxmlファイルをviewにinflateしておき、そこからUI部品のインスタンスを取得しておき、そのインスタンスに関して操作してあげる必要がある。
 AlertDialogにはsetView(R.layout.test_layout)のようにリソースから設定できるが、このようなやり方だとshow()するまでUI部品にアクセスすることができない。そのため、事前にLayoutInflaterでviewのインスタンスを生成しておき、そしてsetView(View)をしたほうがいい。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

//まずはDataStoreのインスタンスを生成して、そこに設定したい内容を設定する var dataStore: TestDialog.DataStore = TestDialog.DataStore().also {

//タイトルを設定する場合 it.setTitle("ぬるぬる") //カスタムレイアウトを設定して、カスタムレイアウトに対するコールバックも設定できる
//ここでは別設定のxmlファイルを読み込んで、そこのbtnDialog01というボタンのインスタンスを取得
it.setView(R.layout.test_dialog_layout) { view ->
//viewにはカスタムレイアウトのviewが入っているのでfindViewByIdでIDからインスタンスを取得できる view.findViewById<Button>(R.id.btnDialog01).setOnClickListener { Log.v("nullpo", "レイアウトのボタンクリック") } }
//posotiveButtonのテキストとコールバックも設定できる it.setPositiveButton("ボタン名") { dialog, witch -> Log.v("nullpo", "positiveButtonクリック") } } var dialog: TestDialog = TestDialog.Builder(dataStore) btnOpenDialog.setOnClickListener {
//ボタンクリックでダイアログを表示 supportFragmentManagerなのに注意が必要 dialog.show(supportFragmentManager, "dialog") } } } class TestDialog() : DialogFragment() { private var mDataStore: DataStore by Delegates.notNull<DataStore>() companion object {
//Dialogの設定する情報が入っているDataStoreクラスのインスタンスを受け取る fun Builder(dataStore: DataStore): TestDialog {
//DataStoreクラスをBundleでやりとりする val bundle: Bundle = Bundle().also { it.putSerializable("DataStore", dataStore) } val testDialog: TestDialog = TestDialog().also { it.arguments = bundle } return testDialog }
//DataStoreクラスのインスタンスを生成するBuilderパターン fun DataStore(): DataStore = DataStore() }
//ここで設定されたメンバ変数はスマホ縦横移動時にも記憶される
//なのでダイアログ情報を設定したクラスを取得してメンバ変数に保存しておく override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mDataStore = arguments?.getSerializable("DataStore") as DataStore }
//ここでAlertDialogに関する様々な設定を行う override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
//Builderの引数がnot nullなので!!をつける val dialogBuilder = AlertDialog.Builder(activity!!)
//レイアウトファイルの設定があったらレイアウトのxmlを読んで、そのviewのインスタンスを所得するためにonAttachLayoutCallbackを呼ぶ mDataStore.mLayoutResId?.let { var view: View = LayoutInflater.from(activity).inflate(it, null) mDataStore.mOnAttachLayoutCallBack?.invoke(view) dialogBuilder.setView(view) } //タイトルとメッセージを設定
//変数がnullだったら設定しない mDataStore.mTitle?.let { dialogBuilder.setTitle(it) } mDataStore.mMessage?.let { dialogBuilder.setMessage(it) } //item関連 mDataStore.mItemsText?.let { dialogBuilder.setItems(mDataStore.mItemsText, mDataStore.mItemsCallBack) } mDataStore.mSingleChoiceText?.let { dialogBuilder.setSingleChoiceItems(mDataStore.mSingleChoiceText, mDataStore.mSingleCheckedItem!!, mDataStore.mSingleChoiceCallBack) } mDataStore.mMultiChoiceText?.let { dialogBuilder.setMultiChoiceItems(mDataStore.mMultiChoiceText, mDataStore.mMultiChoiceItem, mDataStore.mMultiChoiceCallBack) } //ボタン関連 mDataStore.mPositiveButtonText?.let { dialogBuilder.setPositiveButton(mDataStore.mPositiveButtonText, mDataStore.mPositiveButtonCallBack) } mDataStore.mNegativeButtonText?.let { dialogBuilder.setNegativeButton(mDataStore.mNegativeButtonText, mDataStore.mNegativeButtonCallBack) } mDataStore.mNeutralButtonText?.let { dialogBuilder.setNeutralButton(mDataStore.mNeutralButtonText, mDataStore.mNegativeButtonCallBack) } //イベント関連 mDataStore.mOnCalcelCallBack?.let { dialogBuilder.setOnCancelListener(it) } return dialogBuilder.create() }
//AlertDialogに設定する内容を保存するクラス
//Bundleで受け渡しができるようにSerializableを継承しておく class DataStore : Serializable { //タイトルとメッセージ
//基本的にnullを設定しておく。nullじゃないときだけAlertDialogに設定するため internal var mTitle: CharSequence? = null internal var mMessage: CharSequence? = null //アイテム internal var mItemsText: Array<CharSequence>? = null internal var mItemsCallBack: ((DialogInterface, Int) -> Unit)? = null //RadioButton internal var mSingleChoiceText: Array<CharSequence>? = null internal var mSingleCheckedItem: Int? = null internal var mSingleChoiceCallBack: ((DialogInterface, Int) -> Unit)? = null //Checkbox internal var mMultiChoiceText: Array<CharSequence>? = null internal var mMultiChoiceItem: BooleanArray? = null internal var mMultiChoiceCallBack: ((DialogInterface, Int, Boolean) -> Unit)? = null //レイアウトファイル internal var mLayoutResId: Int? = null internal var mOnAttachLayoutCallBack: ((View) -> Unit)? = null //イベント internal var mOnCalcelCallBack: ((DialogInterface) -> Unit)? = null //各種ボタン internal var mPositiveButtonText: CharSequence? = null internal var mPositiveButtonCallBack: ((DialogInterface, Int) -> Unit)? = null internal var mNegativeButtonText: CharSequence? = null internal var mNegativeButtonCallBack: ((DialogInterface, Int) -> Unit)? = null internal var mNeutralButtonText: CharSequence? = null internal var mNeutralButtonCallBack: ((DialogInterface, Int) -> Unit)? = null
//レイアウトxmlファイルを読んで、そのUI部品に対してイベントを設定できるようにするためコールバックする fun setView(layoutResId: Int, listener: (View) -> Unit) { mLayoutResId = layoutResId mOnAttachLayoutCallBack = listener } fun setTitle(title: CharSequence) { mTitle = title } fun setMessage(message: CharSequence) { mMessage = message } fun setItems(items: Array<CharSequence>, listener: ((DialogInterface, Int) -> Unit)) { mItemsText = items mItemsCallBack = listener } fun setSingleChoiceItems(items: Array<CharSequence>, checkItem: Int?, listener: ((DialogInterface, Int) -> Unit)) { mSingleChoiceText = items mSingleCheckedItem = checkItem mSingleChoiceCallBack = listener } fun setMultiChoiceItems(items: Array<CharSequence>, checkItem: BooleanArray, listener: ((DialogInterface, Int, Boolean) -> Unit)) { mMultiChoiceText = items mMultiChoiceItem = checkItem mMultiChoiceCallBack = listener } fun setPositiveButton(message: CharSequence, listener: (DialogInterface, Int) -> Unit) { mPositiveButtonText = message mPositiveButtonCallBack = listener } fun setNegativeButton(message: CharSequence, listener: (DialogInterface, Int) -> Unit) { mNegativeButtonText = message mNegativeButtonCallBack = listener } fun setNeutralButton(messsage: CharSequence, listener: (DialogInterface, Int) -> Unit) { mNeutralButtonText = messsage mNeutralButtonCallBack = listener } fun setOnCancelListener(listener: (DialogInterface) -> Unit) { mOnCalcelCallBack = listener } } }