Kotlin Result + Kotlin Coroutines

最近、業務でKotlin Coroutinesを使うようになりました。 既存のRxによる通信処理を、主にawaitに書き換えたり、新規に作成するAPIをCoroutinesで対応させたり、といった感じです。

取り組みの1例がこちら。先日、GSONも外したので次はKDocあたりをちゃんと生成する予定です。

tech.studyplus.co.jp

Resultクラス

日々日々KotlinとCoroutinesの勉強をしているところなのですが、最近Resultクラスが便利だなーと思っています。

Result - Kotlin Programming Language

Kotlin 1.3から追加されています。任意の型とThrowableを包んでくれるクラスです。 似たようなものとしてはgooglesamplesのandroid-architecture-components内で定義されているResource

github.com

もしくはPagingのサンプルで利用されているNetworkState

https://github.com/googlesamples/android-architecture-components/blob/master/PagingWithNetworkSample/app/src/main/java/com/android/example/paging/pagingwithnetwork/reddit/repository/NetworkState.ktgithub.com

Resultクラスは、上記2クラスに比べると”通信中”を表現する箇所がありません。ですが、その分シンプルにいろんな場面で利用できる形になっています。

好きなところ1 : onFold

github.com

Resultクラスは”成功時”と”失敗時”のそれぞれを扱うクラスです。内部的には成功(型Tのフィールド)と失敗(型Throwableのフィールド)を持っています。 このフィールドにアクセスするときにはgetOrNullexceptionOrNullを利用します。

val result = (Result取得処理)

val successValue = result.getOrNull()
if (successValue =! null) {
    // 成功時の処理
}

val exceptionValue = result.exceptionOrNull()
if (exceptionValue != null) {
    // 失敗時の処理
}

またonSuccessonFailureメソッドが拡張関数として用意されています。

val result = (Result取得処理)

result.onSuccess {
  // 成功時の処理
}

result.onFailure {
  // 失敗時の処理
}

ただ、若干冗長ですよね。そんなわけでfoldです。

val result = (Result取得処理)

result.fold(
    onSuccess = {
        // 成功時の処理
    },
    onFailure = {
        // 失敗時の処理
    }
)

サイコー。

好きなところ2 : runCatching

RxJavaからKotlin Coroutinesに書き換えていると、若干不満なのがtry-catch構文を使わなければならないところだと思います。せっかく処理が追いやすくなるようにRxからKotlin Coroutinesに置き換えたのに、そういう不満は勿体無いですよね。

ということで、runCatchingを使いましょう。

val result = runCatching {
    (Result取得処理)
}

処理中に発生した例外はfailureで、処理結果がsuccessで取得できます。先述のfoldと組み合わせると。

runCatching {
    (Result取得処理)
}.fold(
    onSuccess = {
        // 成功時の処理
    },
    onFailure = {
        // 失敗時の処理
    }
)

サイコー。

その他

mapCatchingなど、取得結果を加工する拡張関数もいくつか用意されています。 通信処理結果をRepository層からViewModel層へ汎用的な形で返し、ViewModel層で加工してViewへ渡すといった処理が描きやすそうな雰囲気です。 Kotlin 1.3から追加されただけはあるなーと。

ResourceNetworkStateから移行しようとするとLOADINGの表現だけ悩みが発生します。こちら、まだ試行錯誤途中なので、なにかアイデアがあれば教えていただきたいです。

一言

スマブラ面白すぎる。amiibo 63種セット買い損ねたのがすごい残念。