yujiro's blog

「インターネット上で正しい答えを得る最善の方法は、質問することではない。間違った答えを投稿することだ」by ウォード・カニンガム

RxJava での購読解除はuber のAutoDisposeを使ったほうが良さそう、という話

現在、仕事場のAndroid のコードでは2種類の購読解除方法を使っている

1つめは、bindToLifeCycle、bindUntilEvent を使う方法

single
    .compose(bindToLifeCycle())
    ...

もう一つは、Autodispose を使う方法

https://github.com/uber/AutoDispose

single
    .as(AutoDispose.autoDisposable(RxLifecycleInterop.from(this).requestScope()))
    ...

※ 実際にはPresenter で購読開始するので、view を引数に渡している事が多い。


1つめのほうは、RxLifecycle ( https://github.com/trello/RxLifecycle ) を使っているんだけど、 厳密にいうと購読解除はしてくれなくて、onCompleted や onError が呼ばれてしまう。

Observable, Flowable and Maybe - emits onCompleted() Single and Completable - emits onError(CancellationException)

from : https://github.com/trello/RxLifecycle#unsubscription

これは問題で、例えばSingleだったら「ライフサイクルの変化でサイレントな購読解除を望んでいたんだけど、実はonError が呼ばれてるから裏でアラートがでてたよね」ということが往々にしてありえる。


なので、2つめのAutoDispose を使いたいところ。

「AutoDispose 使用時には、onError は呼ばれないの?」という点が気になっていたが、テストコード書いて検証した結果、AutoDispose を使えばサイレントに購読解除された。

以下検証コード

    lateinit private var mActivity: StartActivity

    @get:Rule
    public var mActivityRule = ActivityTestRule(StartActivity::class.java)

    @Before
    fun setUp() {
        mActivity = mActivityRule.getActivity() as StartActivity
    }

    @Test
    fun testStart() {
        getSingle()
            .subscribeOn(Schedulers.newThread())
            .compose(mActivity.bindToLifecycle()) // ココが変わる
            .autoDisposable(mActivity) // ココが変わる
            .subscribe({
                Log.d("Success", it)
            }, {
                Log.d("Error", "uoooo")
            })
        mActivity.finish()
    }

    fun getSingle(): Single<String> {
        return Single.create {
            Thread.sleep(3000)
            it.onSuccess("Hoge!")
        }
    }

結果、

.compose(mActivity.bindToLifecycle())

を使った場合、onError(CancellationException e) がコールされた。

そのあとで、StartActivityのonDestroy が呼ばれた。

.autoDisposable(mActivity) 

を使用した場合、onError が呼ばれずにStartActivityのonDestroy が呼ばれた。