(追記)
この記事のコードはダイアログの再生成時に正常に動作しません。
特別な事情がない限り使用しないことをおすすめします。
はじめに
タイトルの通りですが、DialogFragmentで生成したダイアログのボタンクリックをRxAndroid(RxJava)のObservableとして扱いたくていろいろ試した結果のメモ。
Observableにしたいけど…
個人的な好みの問題だとは思いますがDialogFragmentをshowしたタイミングでObservableを返してほしいと思っています。
ただ、DialogFragmentにおいてダイアログ本体の生成はonCreateDialogで行っているためshowのタイミングではダイアログは生成済みです。
このタイミングでダイアログにボタン&クリックのリスナーを追加してもボタン自体が表示されません。
showの実装を見ると、自分自身をFragmentManagerに追加しているだけなので当然といえば当然ですが…
なので、onCreateDialogで生成したダイアログのボタンクリック時の動作をshowするタイミングで置き換えることにしました。
ObservableなDialogFragment(のダイアログ)
DialogFragment側の実装
showの代わりに実行するshowObservableDialogを実装します。
onCreateDialogの時点では、仮の何もしない関数を突っ込んでおいてObservable.createするタイミングでonNext等々を実行する関数に置き換えます。
public class LoginDialog : DialogFragment() {
private var mOnPositiveClick = { }
private var mOnNegativeClick = { }
fun showObservableDialog(manager: FragmentManager, tag: String?): Observable<Boolean> {
super.show(manager, tag)
return Observable.create<Boolean> {
mOnPositiveClick = {
it.onNext(true)
it.onCompleted()
this.dismiss()
}
mOnNegativeClick = {
it.onCompleted()
this.dismiss()
}
}.subscribeOn(AndroidSchedulers.mainThread())
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog? {
return AlertDialog.Builder(getActivity())
.setTitle(R.string.login)
.setMessage(R.string.login_message)
.setPositiveButton(R.string.login, { dialog, witch -> mOnPositiveClick() })
.setNegativeButton(R.string.cancel, { dialog, witch -> mOnNegativeClick() })
.create()
}
}
呼び出し側の実装
今回はこのダイアログが起点になるので、最初にshowObservableDialogしてログインボタンが押されたら続く処理を実行します。
ここではWebViewでOAuth認証してユーザ情報を取得しています。
LoginDialog().showObservableDialog(getSupportFragmentManager(), null)
.flatMap { retrieveRequestToken() }
.flatMap { showLoginWebView(it) }
.flatMap { retrieveAccessToken(it) }
.flatMap { getUserInfo(it) }
.observeOn(AndroidSchedulers.mainThread())
.subscribe (
{ success -> this.finish() },
{ error -> toast("Error!") } )
おわり
面倒なことやってるけど、思ったよりすっきり書けた。
今回の例だとダイアログが起点なのでそこまでの利点は無いけど、処理の途中でダイアログが必要なときは役に立つと思う。
JavaだとInterface使えばやれそう?(試してない)