コルーチンを利用した非同期処理
参考: AndroidでのKotlinコルーチン
参考: 図で理解するKotlinコルーチン
コルーチン
非同期処理
が含まれるブロック{...}
(=コルーチンスコープ
)内で、非同期処理
の実行中に、同期処理
を中断できる仕組み(=デザインパターン
)。
UIスレッド
の処理によって呼び出された、ワーカースレッド
での処理を含む非同期処理
のまとまり。
コルーチン
を起動する、UIスレッド
で動作する処理を処理A
、
処理A
によって呼び出されたワーカースレッド
で動作する処理を処理B
、
処理B
によって呼び出されたUIスレッド
で動作する処理を処理C
とすると、
処理C
は処理B
の終了を待つ必要があるため、同一処理ブロック{}
でまとめて管理するのが望ましく、この処理のまとまりをコルーチン
と呼ぶ。
また、処理B
と処理C
は互いに異なるスレッド
上で動作するため、双方から見て非同期処理
と言える。
コルーチンスコープ
コルーチン
の生存可能環境。
コルーチン
を管理しており、コルーチン
の起動や実行中止を行う。
ViewModel
でコルーチンを定義した場合はViewModel
クラスのviewModelScope
プロパティ、
アクティビティ
でコルーチンを定義した場合はActivity
クラスのlifecycleScope
プロパティがコルーチンスコープ
にあたる。
コルーチンを利用した非同期処理の実装
コルーチン
を利用した非同期処理
を実装する手順は、以下の通り。
Gradle Scripts/build.gradle(Module)
のdependencies
ブロックに、コルーチン
の実装に必要な追加ライブラリを記述コルーチン
の定義コルーチンスコープ
から2.で定義したコルーチン
を起動
build.gradle(Module)への追加ライブラリの記述
コルーチン
の実装に必要な機能は標準SDK
で定義されていないため、追加ライブラリをGradle Scripts
フォルダのbuild.gradle(Module)
ファイルに記述する必要がある。
また、ライブラリ
のバージョンは以下サイトを参考に、安定版の最新バージョン番号に書き換える。
Kotlinコルーチン
AndroidX Lifecycle
サンプルコード
...
dependencies {
// Kotlinコルーチン
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0"
// AndroidX Lifecycle
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
...
}
コルーチンの定義
参考: CoroutineScope
非同期処理
を行う処理を記述する際、
ワーカースレッド
での動作を保証する@WorkerThread
アノテーションの記述に加え、
呼び出し元スレッド
での処理を中断させながら、指定スレッド
で処理を実行できるwithContext()
メソッドを利用する。
なお、withContext()
メソッドは内部的にsuspend
キーワードが付与されているため、withContext()
メソッドを利用する親メソッドにもsuspend
キーワードを付与する必要がある。
定義
// スレッドを分離して処理を実行
// <- 内部的にsuspendキーワードが付与
suspend fun <T> withContext(
context: CoroutineContext,
block: suspend CoroutineScope.() -> T
): T
// パラメータ
// context: 分離先スレッド(Dispatchersクラス定数)
// block: スレッドを分離して実行する処理
Dispatchersクラス定数
クラス定数 | 内容 |
---|---|
Dispatchers.Main |
UIスレッド 用途: UI 操作 |
Dispatchers.IO |
ワーカースレッド (I/Oスレッド )用途: Room コンポーネントファイルの 読み書き ネットワークオペレーション
|
Dispatchers.Default |
ワーカースレッド (Defaultスレッド )用途: CPU負荷 の高い作業 |
サンプルコード
// 非同期(=ワーカースレッド)で実行する処理
// -> ワーカースレッドで動作することを明示的に記述(@WorkerThreadアノテーション)
// suspend: 実行中は元スレッド(=UIスレッド)の他の処理を中断させる
@WorkerThread
private suspend fun backgroundTaskRunner(): String {
// ワーカースレッドで取得した値
val returnVal = withContext(Dispatchers.IO) {
... // ワーカースレッドで値を取得
}
// 取得した値を返却
return returnVal
}
suspendシグネチャ
suspend
シグネチャが付与されたメソッド
の実行中に、メソッドの呼び出し元スレッド
での処理を中断させるキーワード。
コルーチンスコープによるコルーチンの起動
アクティビティ
でコルーチン
を定義した場合、アクティビティ
がもつlifecycleScope
プロパティを利用してコルーチン
を起動する。
ViewModel
でコルーチンを定義した場合、ViewModel
クラスのviewModelScope
プロパティを利用してコルーチン
を起動する。
定義
CoroutineScope.launch(
context: CoroutineContext
start: CoroutineStart
block: suspend CoroutineScope.() -> Unit
)
// パラメータ
// context: コルーチンスコープへの追加コンテキスト
// -> 未指定の場合はDispatchers.Default(コルーチンスコープから継承)
// start: コルーチンの開始タイミング(CoroutineStartクラス定数)
// -> 未指定の場合はCoroutineStart.Default(即時実行)
// block: 起動するコルーチン
サンプルコード
@UiThread
private fun asyncExecute() {
// アクティビティのコルーチンスコープによるコルーチンの起動
lifecycleScope.launch {
// コルーチン
// ワーカースレッドで動作する非同期処理
backgroundTaskRunner()
// UIスレッドで動作する非同期処理
postBackgroundTaskRunner()
}
}
コルーチンを利用した非同期処理の実装まとめ
// UIスレッドで動作する非同期処理を含む処理
@UiThread
private fun asyncExecute() {
// ライフサイクルに最適化されたスコープを利用してコルーチンを起動
lifecycleScope.launch {
// 非同期(=ワーカースレッド)で行う処理
backgroundTaskRunner()
// 非同期処理後に同期(=UIスレッド)で行う処理
postBackgroundTaskRunner()
}
}
// ワーカースレッドで動作する処理(非同期処理)
@WorkerThread
private suspend fun backgroundTaskRunner() {
withContext(Dispatchers.IO) {
... // 非同期処理
}
}
// 非同期処理後にUIスレッドで動作する処理(同期処理)
@UiThread
private fun postBackgroundTaskRunner() {
... // 同期処理
}