【Android Studio/Kotlin Coroutines】Jobの使い方!遅延実行やキャンセル
この記事からわかること
- Android StudioのKotlin Coroutinesの実装方法の使い方
- 非同期処理を実装する方法
- Jobとは?
- コルーチンの管理方法
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
公式リファレンス:Kotlin coroutines on Android
環境
- Android Studio:Flamingo
- Kotlin:1.8.20
Kotlin Coroutinesとは?
Kotlin CoroutinesとはAndroidアプリ開発で非同期処理を実装できる公式ライブラリです。また「コルーチン」という言葉自体はAndroidで使用できる並行実行のデザインパターンのことを指しており、日本語に訳すと「特定の機能を担うルーチン」という的な意味になると思います。
Kotlin Coroutinesを使用することでこれまでコールバックなどで実行していたネットワーク処理やデータベースへの書き込み処理(I/O)、また処理に時間のかかるものなどを非同期的に(通常の流れとは異なる流れで)実行することでメインスレッドを活かし、アプリの対話性と生産性の向上を期待することができます。詳細は以下の記事を参考にしてください。
Jobとは?
interface Job : CoroutineContext.Element
Kotlin CoroutinesではJobという単位でコルーチンを一意に識別し、そのライフサイクルが管理されています。Jobを操作することで処理の開始、キャンセル、完了を制御することが可能になります。
コルーチンをJobインスタンスとして管理するためにはグローバル関数Job()
を使用するかCoroutineBuilderであるlaunch
やasync
を使用し、その返り値であるJobインスタンス(asyncのDeferred
オブジェクトもJobの一種)を保持するだけです。処理の実行自体は非同期で即座に開始しますが時間のかかる処理の場合、一定時間経過でcancel
メソッドを使用することでコルーチンの実行をキャンセルすることができます。
import kotlinx.coroutines.*
fun main() {
val job = GlobalScope.launch {
repeat(10) { i ->
println("Job is running: $i")
delay(1000)
}
}
// 3秒後にジョブをキャンセルする
runBlocking {
delay(3000)
}
job.cancel()
println("Main function finished")
}
出力結果
Job is running: 0
Job is running: 1
Job is running: 2
Job is running: 3
Main function finished
JobインスタンスはそのJobの状態(ステータス)を保持しておりisActive
などのプロパティから状態を取得することができます。
import kotlinx.coroutines.*
fun main() {
runBlocking {
// Jobインスタンスを取得
val childJob1 = launch { createRemoteData() }
// Deferredインスタンスを取得
val childJob2 = async { fetchDataFromRemote() }
print(childJob1.isActive) // true
// Jobをキャンセルする
childJob1.cancel()
print(childJob1.isActive) // false
print(childJob1.isCompleted) // false
print(childJob1.isCancelled) // true
// Deferredインスタンスから中身を取得(await:非同期が終了するまで待機)
val remoteData = childJob2.await()
print(childJob2.isActive) // false
print(childJob2.isCompleted) // true
print(childJob2.isCancelled) // false
print("$remoteData")
}
}
suspend fun createRemoteData() {
delay(1000)
print("リモートサーバーにデータを作成")
}
suspend fun fetchDataFromRemote(): String {
delay(2000)
return "リモートサーバーからフェッチ"
}
Jobのステータス
Jobのステータスは以下のように6種類に分かれています。それぞれの状態でのプロパティの値も以下のように変化します。launch
やasync
で生成したJobインスタンスは最初からActive
状態になっているようです。
State | isActive | isCompleted | isCancelled |
---|---|---|---|
New (optional initial state) | false | false | false |
Active (default initial state) | true | false | false |
Completing (transient state) | true | false | false |
Cancelling (transient state) | false | false | true |
Cancelled (final state) | false | true | true |
Completed (final state) | false | true | false |
Jobの親子関係
Jobは親子関係を持った階層構造で管理することができ、親Jobの中に複数の子Jobを保持することが可能です。親のJobが明示的にキャンセルされた場合はその親が保持している子Jobも全てキャンセルされます。
fun main() {
val parentJob = Job()
val childJob = GlobalScope.launch(parentJob) {
repeat(10) { i ->
print("Job is running: $i")
delay(1000)
}
}
// 親Jobをキャンセルする (子Jobは出力されない)
parentJob.cancel()
print("Main function finished")
}
Jobが完了した後に処理を実行する:invokeOnCompletion
abstract fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle
Jobが完了状態などに移行した際に処理を実行したい場合はinvokeOnCompletion
メソッドを使用します。CompletionHandler
からはThrowable?
型で例外を受け取ることが可能です。
parentJob.invokeOnCompletion { throwable ->
if (throwable != null) {
// ジョブが例外とともに完了した場合の処理
} else {
// ジョブが正常に完了した場合の処理
}
}
Jobを遅延実行する方法
生成したJobを即座に開始するのではなく遅延して実行させたい場合はlaunch
やasync
の引数start
にCoroutineStart.LAZY
を指定します。何も指定しない場合は即座にコルーチンが実行され「Coroutine is running」が出力されます。
fun main() {
val job = GlobalScope.launch {
println("Coroutine is running")
}
}
CoroutineStart.LAZY
を指定するとjob.start()
がされるまで実行を遅延させることができます。とjob.start()
を呼び出さないとコルーチン内の処理は実行されません。
fun main() {
val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
println("Coroutine is running")
}
job.start()
}
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。