Kotlin Coroutinesのasync/awaitの挙動を確認してみる
RxjavaのコードをCoroutinesで書き直せるのか?など調べていくうちにCoroutinesでの動き方に曖昧に理解しているところがあったので動かしてみた結果をメモしておく。
- Kotlin version : 1.3.31
- Coroutines version: 1.2.1
とても参考にしました :bow: satoshun.github.io
private suspend fun completeFirst(): String { delay(2000) Timber.d("completeFirst ") return "completeFirst" } private suspend fun completeSecond(): String { delay(1000) Timber.d("completeSecond") return "completeSecond" }
前提としてこういったsuspend関数があるとする。
素直に実行する
uiScope.launch { completeFirst() completeSecond() }
Output: completeFirstが実行された後にcompleteSecondが実行される
D/MainActivity: completeFirst D/MainActivity: completeSecond
asyncをつける
uiScope.launch { async{ completeFirst() } async{ completeSecond() } }
Output: pararellに実行されるのでcompleteSecondの方が先にlogが出る
D/MainActivity: completeSecond D/MainActivity: completeFirst
Exceptionをthrowするとき
suspend関数内でExceptionを吐くときの挙動を確認する。
private suspend fun completeFirst(): String { delay(2000) Timber.d("completeFirst ") throw Throwable("test first") return "completeFirst" } private suspend fun completeSecond(): String { delay(1000) Timber.d("completeSecond") return "completeSecond" }
uiScope.launch { completeFirst() completeSecond() }
Output: completeSecondは実行されず、completeFirstのthrowでアプリはクラッシュする
D/MainActivity: completeFirst E/AndroidRuntime: FATAL EXCEPTION: main java.lang.Throwable: test first
asyncをつける
completeSecondでも例外を吐くときを考える
private suspend fun completeFirst(): String { delay(2000) Timber.d("completeFirst ") return "completeFirst" } private suspend fun completeSecond(): String { delay(1000) Timber.d("completeSecond") throw Throwable("test first") return "completeSecond" }
uiScope.launch { async{ completeFirst() } async{ completeSecond() } }
Output: asyncをつけても例外をthrowされた時点でアプリはcrashする
D/MainActivity: completeSecond E/AndroidRuntime: FATAL EXCEPTION: main java.lang.Throwable: test first
try-catchをつける
uiScope.launch { try{ async{ completeFirst() } async{ completeSecond() } } catch (th:Throwable) { Timber.e(th) } }
Output: crashする。async内で起こったcrashはcatchできない。
asyncの中でtry-catch/runCatching
uiScope.launch { async{ runCatching{completeFirst()} } async{ runCatching{completeSecond()} }
Output:これでアプリはcrashしなくなる。
async{runCatching{completeFirst()}}
の返り値はResult
型で、isFailure
isSuccess
で結果がわかるのでこれを組み合わせればRxJavaでいうzip
とかcompleteDelaymerge
のような動きもかけそう。