AlertDialogで項目選択後に勝手に閉じないようにする方法
AlertDialogでsetItems()した項目をタップしたときにdismiss()以外で勝手に閉じないようにする方法
Created at

589 Words
⚠️

前提

次のようにして生成したダイアログでは、表示された項目をタップすると引数の関数を実行した後ダイアログは自動的に閉じる。
(勿論DialogFragmentを使用する場合も同様。)

AlertDialog.Builder(context, R.style.AlertDialogStyle)
    .setItems(labels) { dialog, which ->
        // 項目をタップしたときの処理
    }
    .create()

問題

通常これで困ることはあまりないが、非同期的な処理を行いたい場合には注意が必要になる。
DialogFragmentが持っているlifecycleScopeや、ViewModelviewModelScopeを使用してコルーチンを非同期に実行すると、処理がすべて完了する前にダイアログが破棄されてコルーチンがキャンセルされる場合があるためだ。

解決策

このような場合、まぁ一番手っ取り早く問題を解決できそうなのはGlobalScopeでコルーチンを実行することだが、
次のようにして「コルーチンが完了するまでダイアログを閉じない」という方法をとることもできる。

AlertDialog.Builder(context, R.style.AlertDialogStyle)
    .setItems(labels, null)
    .show()
    .also { dialog ->
        dialog.listView.setOnItemClickListener { adapterView, view, which, l ->
            lifecycleScope.launch(Dispatchers.Main) {
                // 何かいろいろ処理

                // 完了後にダイアログを明示的に閉じる
                dismiss()
            }
        }
    }

余談

「OK」「キャンセル」などのネガティブ・ポジティブボタンの処理についても似たようにすることでボタン押下時にダイアログを閉じるかどうかを制御できる。

AlertDialog.Builder(context, R.style.AlertDialogStyle)
    .setNegativeButton(R.string.dialog_cancel, null)
    .setPositiveButton(R.string.dialog_ok, null)
    .show()
    .also { dialog ->
        dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
            // ポジティブ
            // dismiss()が呼ばれなければ閉じない
            dismiss()
        }

        dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setOnClickListener {
            // ネガティブ
            // dismiss()が呼ばれなければ閉じない
            dismiss()
        }
    }

See Also