RxJavaを使ったエラーハンドリングをどうするか その1
前提
- RxJavaでは例外が投げられた時、Observable#subscribeの引数onErrorにThrowableで渡って来る。
例
class ApiClient { fun fetchSomeData() : Single<SomeData> { // 取得処理 } }
利用側
apiClient.fetchSomeData() .subscribe ( { data : SomeData -> /** 成功処理 */ }, { t: Throwable -> /** エラーハンドリング */ })
問題
- どのようなエラーが返って来るかという情報がメソッド定義にない。
- 実装を読まないとわからない ( = カプセル化されてない)
- 大きめのコードの場合実装を追うのが大変
- 実装を読まないとわからない ( = カプセル化されてない)
解決策
@OnError アノテーションを定義して、ハンドリングして欲しい例外はメソッド定義につける
/** * ハンドリングするべき例外をonErrorに流す場合、メソッドの返り値に付与する */ @Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.SOURCE) @MustBeDocumented annotation class OnError(vararg val klass: KClass<*>)
ハンドリングして欲しい例外の基準
ユーザーが回復可能かどうか。回復可能な場合、ハンドリングしてユーザーに回復方法を伝える価値がある。 以下の Recoverable Error の例が参考になった。
例
class ApiClient { @OnError(NetworkException::class, ApiException::class ) fun fetchSomeData() : Single<SomeData> { // 取得処理 } }
利用側
apiClient.fetchSomeData() .subscribe ( { data : SomeData -> /** 成功処理 */ }, { t: Throwable -> when (t) { is NetworkException -> toast("ネットワーク接続状態を確認してください。") is ApiException -> toast("リクエストに失敗しました。時間を置いて再度お試しください。") else -> toast("失敗しました") //想定してない例外なのでとりあえずな文言を出して、裏でクラッシュレポーティングツールとかに伝えるのが良いんじゃないかと思う。 } })