この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
まえがき
Coroutinesは、Coroutines are experimental in Kotlin 1.1で、実験的な機能ですのでプロダクトにはまだ早いですが、とても便利なので今のうちから備えておきたいところです。
Coroutines - Kotlin Programming Language
kotlinx.coroutines/coroutines-guide.mdを写経しながら勉強しています。
サンプルアプリを作りながら、ある程度パターンが見えてきました。
コルーチン
Coroutines(コルーチン)は中断・再開可能な関数です。
こちらに丁寧な説明があります。導入の仕方もあります。
Kotlin+Androidでasync/await - Qiita
Androidで使用する場合の良さそうなパターンがありましたので、ご紹介します。
MVPでもMVVMでも、使用できるパターンです。
概要
MVPでもMVVMでも大まかにいってこんな処理をすると思います。
UIから(タップなど)イベント -> 重たい処理(Webのapiを叩くなど) -> 結果をUIに反映
コルーチンがない現状は、RxJavaなどを用いて処理していると思います。
RxJavaの例
fun click(){
view.showLoading()
repository.api()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
view.hideLoading()
view.showSuccess(it)
}, {
view.showError(it)
})
}
パターン
重たい処理(Webのapiを叩くなど)の部分は処理している間は中断して他の処理をしてもらうようにsuspendをつけます。
class Repository{
suspend fun api() : Response{
//重たい処理
return Response()
}
}
UIから(タップなど)イベントと結果をUIに反映の部分はUIスレッドで行えるようにします。
launch(UI)をつかってUIスレッドで処理するように指定します。
fun click() = launch(UI) {
}
そして、RepositoryのapiをUIスレッド以外で処理するようにCommonPoolを使用します。CommonPoolは新しいスレッドだと思ってください。apiはResponseを返すのでlaunchではなく asyncをつかって処理結果を受け取れるします。await()を使って、処理が終わるまで待ちます。その間は、中断され、処理が終わった時に再開されます。(非同期っぽく処理できる)
fun click() = launch(UI){
val response = async(CommonPool){
repository.api()
}.await()
}
その他付属品をつけてあげて
fun click() = launch(UI) {
view.showLoading()
val repository = Repository()
try {
val response = async(CommonPool) {
repository.api()
}.await()
view.hideLoading()
view.showSuccess(response)
}catch (e: Throwable){
view.view.showError(e)
}
}
これで完成!
っと言いたいところだけど、このままだと、activityでonStopでJobをキャンセルしたいときにCommonPoolの処理がキャンセルされません。キャンセルできるように修正する必要があります。
こちらに丁寧な説明があります。AndroidでKotlin Coroutineを非同期で使うときの注意 – STAR_ZERO – Medium
fun click() = launch(UI) {
view.showLoading()
val repository = Repository()
try {
val response = async(context + CommonPool) {
repository.api()
}.await()
view.hideLoading()
view.showSuccess(response)
}catch (e: Throwable){
view.view.showError(e)
}
}
まとめ
ソースコードが同期的な書き方でとても読みやすいです。非同期で依存関係がある場合コールバック地獄になりがちでしたが、とても簡潔に記述できるようになります。次回コルーチンでのUnitTestについて書きたいと思います。