最近、業務でKotlin Coroutinesを使うようになりました。 既存のRxによる通信処理を、主にawaitに書き換えたり、新規に作成するAPIをCoroutinesで対応させたり、といった感じです。
取り組みの1例がこちら。先日、GSONも外したので次はKDocあたりをちゃんと生成する予定です。
Resultクラス
日々日々KotlinとCoroutinesの勉強をしているところなのですが、最近Result
クラスが便利だなーと思っています。
Result - Kotlin Programming Language
Kotlin 1.3から追加されています。任意の型とThrowable
を包んでくれるクラスです。
似たようなものとしてはgooglesamplesのandroid-architecture-components内で定義されているResource
。
もしくは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
Result
クラスは”成功時”と”失敗時”のそれぞれを扱うクラスです。内部的には成功(型Tのフィールド)と失敗(型Throwableのフィールド)を持っています。
このフィールドにアクセスするときにはgetOrNull
やexceptionOrNull
を利用します。
val result = (Result取得処理) val successValue = result.getOrNull() if (successValue =! null) { // 成功時の処理 } val exceptionValue = result.exceptionOrNull() if (exceptionValue != null) { // 失敗時の処理 }
またonSuccess
とonFailure
メソッドが拡張関数として用意されています。
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から追加されただけはあるなーと。
Resource
やNetworkState
から移行しようとするとLOADING
の表現だけ悩みが発生します。こちら、まだ試行錯誤途中なので、なにかアイデアがあれば教えていただきたいです。