LoginSignup
1
1

More than 5 years have passed since last update.

RxJavaカスタムオペレータ作成時の自分用テンプレ(ただしKotlinで)

Posted at

RxJavaでカスタムオペレータを作るときの自分用テンプレ。

少しだけ解説すると、noOpは何も加工しません。
myMapは、Observable#map(Function<? super T,? extends R> mapper)と機能は変わりません。
errMapは、流れてきたエラー捕まえて加工したあと、再度エラーを流します。

カスタムオペレータを書く動機になったのは、そのオペレータのうちerrMapです。
流れてきたExceptionを加工したくなったときに、Observableでは提供されていないようなので自作しました。

class LiftTest {
    fun <T> Observable<T>.noOp(): Observable<T> {
        return lift { observer ->
            object : Observer<T> {
                override fun onComplete() { return observer.onComplete() }
                override fun onSubscribe(d: Disposable) { return observer.onSubscribe(d) }
                override fun onNext(t: T) { return observer.onNext(t) }
                override fun onError(e: Throwable) { return observer.onError(e) }
            }
        }
    }

    fun <U, D> Observable<U>.myMap(func: (U) -> D): Observable<D> {
        return lift { observer ->
            object : Observer<U> {
                override fun onComplete() { return observer.onComplete() }
                override fun onSubscribe(d: Disposable) { return observer.onSubscribe(d) }
                override fun onNext(t: U) { return observer.onNext(func(t)) }
                override fun onError(e: Throwable) { return observer.onError(e) }
            }
        }
    }

    fun <T> Observable<T>.errMap(func : (Throwable) -> Throwable): Observable<T> {
        return lift { observer ->
            object : Observer<T> {
                override fun onComplete() { return observer.onComplete() }
                override fun onSubscribe(d: Disposable) { return observer.onSubscribe(d) }
                override fun onNext(t: T) { return observer.onNext(t) }
                override fun onError(e: Throwable) { return observer.onError(func(e)) }
            }
        }
    }

    @Test
    fun カスタムオペレタのテスト() {
        Observable
                .just(1)
                .noOp()
                .test()
                .assertValues(1)
        Observable
                .just(1)
                .myMap { it + 2 }
                .test()
                .assertValues(3)
        Observable
                .just("abc")
                .myMap { it.count() }
                .test()
                .assertValues(3)
        Observable
                .just(1)
                .errMap { RuntimeException(it) }
                .test()
                .assertValues(1)
        Observable
                .error<Int>(Exception())
                .errMap { RuntimeException(it) }
                .test()
                .assertError(RuntimeException::class.java)
    }
}

もう少しerrMapを作りたくなった背景を書いておきます。
Retrofit2のHttpException#response()#errorBody()のエラーレスポンスの中味を2回読む必要がありました。
しかし、OkHttp3のResponseBody#string()メソッドが破壊的なため、2回コールしたいけど1回しか許されていません。自作ExceptionでいったんResponseBodyの文字列を退避する必要に迫られ、そのときerrMapで自作Exceptionに変換したという次第です。

Kotlinの拡張関数使って、Observableのメソッドを拡張してます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1