RxJavaでPresenterがViewを購読するスタイル
下記を見ながらMVPで書くぞ、という練習をしている。
その中で、ViewとPresenterを書いてるときに、このあたりの関係をストリームでやれたら気持ちいのかなあと思い試してた。
とりあえずは、TwitterをプロバイダにしたFirabeseのユーザ認証。 Presenterはこんな感じ
interface Presenter { fun startSubscribe() }
ビューはこんな感じ、
interface LoginView { fun twitterAuthObservable(): Observable<TwitterSession> fun showLoginSuccess(session : TwitterAuth) fun showLoginFailure(throwable : Throwable) }
showHogeはログイン成功、失敗時の表示をお願いという処理。
twitterAuthObservableはTwitter認証に成功したら発火するストリーム
Presenter実体はこんな感じ。
class LoginPresenter(private val mView: LoginView) : Presenter { override fun startSubscribe() { mView.twitterAuthObservable().subscribe({ t -> FirebaseLoginUsecase(auth).run().subscribe( { t -> TwitterAuthRepositoryImp().saveTwitterAuth(t) mView.showLoginSuccess(t) }, { t -> loginFailure(t) } ) }, { throwable -> loginFailure(throwable) }) } fun loginFailure(throwable : Throwable) { mView.showLoginFailure(throwable) } }
startSubscribeが呼ばれると、ビューのストリームを購読し始める。
Twitter認証が終わったらFirebaseのログインを行うUseCaseに渡して処理する。
成功したら情報をどこかに保存しつつ、ログイン成功画面へ。 失敗だったらログイン失敗画面へ。
ビューの実体はこんな感じ。
class LoginActivity : AppCompatActivity(), LoginView { val mTwitterLoginButton: TwitterLoginButton by bindView(R.id.twitter_login_button) val mPresenter: Presenter = LoginPresenter(this) val mLoginStream: BehaviorSubject<TwitterSession> = BehaviorSubject.create() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_login) mTwitterLoginButton.callback = object : Callback<TwitterSession>() { override fun success(result: Result<TwitterSession>) = mLoginStream.onNext(result.data) override fun failure(exception: TwitterException) = mLoginStream.onError(exception) } mPresenter.startSubscribe() } override fun twitterAuthObservable(): Observable<TwitterSession> = mLoginStream override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) mTwitterLoginButton.onActivityResult(requestCode, resultCode, data) } override fun showLoginSuccess(session: TwitterAuth) { Toast.makeText(this, "ログインに成功しました", Toast.LENGTH_LONG).show() } override fun showLoginFailure(throwable: Throwable) { Toast.makeText(this, "ログインに失敗しました", Toast.LENGTH_LONG).show() } }
よくあるonCreateでビューにListnerとかcallbackを与えてあげる処理。 コールバック内では、ロジックは書かずに用意したBehaviourSubjectに流してもらう。 全部終わったらPresenterに購読してもらう。
今まではViewが中でPresenterの特定のメソッドを呼ぶという感じだったけど、今回はViewはPresenterのことをほとんど知らなくなった。 クリックしたら何が呼ばれるとか、認証から帰ってきたら何が始まるか、とかは全部Presenter側のコードを読めば済む。
とはいえ、基本ViewとPresenterは1:1の関係で、使いまわしをすることもないと思うのでお互いが依存しあっててもまあいいんじゃないかな・・という気持ちもある。
とりあえずこれでやって辛くなってきたらまたブログにしたためよう