IntelliJ IDEA を使用して Kotlin Flow をデバッグする – チュートリアル
このチュートリアルでは、IntelliJ IDEA を使用して Kotlin Flow を作成しデバッグする方法を説明します。
このチュートリアルは、コルーチンとKotlin Flowの概念に関する事前知識があることを前提としています。
Kotlin Flow を作成する
低速なエミッターと低速なコレクターを持つ Kotlin Flow を作成します。
IntelliJ IDEA で Kotlin プロジェクトを開きます。プロジェクトがない場合は、作成してください。
Gradle プロジェクトで
kotlinx.coroutines
ライブラリを使用するには、build.gradle(.kts)
に次の依存関係を追加します。kotlindependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") }
groovydependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2' }
他のビルドシステムについては、
kotlinx.coroutines
README の指示を参照してください。src/main/kotlin
にあるMain.kt
ファイルを開きます。src
ディレクトリには Kotlin のソースファイルとリソースが含まれています。Main.kt
ファイルには、Hello World!
を出力するサンプルコードが含まれています。3つの数値の Flow を返す
simple()
関数を作成します。- CPU を消費するブロッキングコードを模倣するために、
delay()
関数を使用します。この関数は、スレッドをブロックすることなくコルーチンを 100 ミリ秒間サスペンドします。 for
ループ内でemit()
関数を使用して値を生成します。
kotlinimport kotlinx.coroutines.* import kotlinx.coroutines.flow.* import kotlin.system.* fun simple(): Flow<Int> = flow { for (i in 1..3) { delay(100) emit(i) } }
- CPU を消費するブロッキングコードを模倣するために、
main()
関数内のコードを変更します。- コルーチンをラップするために、
runBlocking()
ブロックを使用します。 collect()
関数を使用して発行された値を収集します。- CPU を消費するコードを模倣するために、
delay()
関数を使用します。この関数は、スレッドをブロックすることなくコルーチンを 300 ミリ秒間サスペンドします。 println()
関数を使用して、Flow から収集された値を出力します。
kotlinfun main() = runBlocking { simple() .collect { value -> delay(300) println(value) } }
- コルーチンをラップするために、
Build Project をクリックしてコードをビルドします。
コルーチンをデバッグする
emit()
関数が呼び出されている行にブレークポイントを設定します。画面上部の実行構成の隣にある Debug をクリックして、コードをデバッグモードで実行します。
Debug ツールウィンドウが表示されます。
- Frames タブにはコールスタックが含まれています。
- Variables タブには現在のコンテキストの変数が含まれています。Flow が最初の値を発行していることがわかります。
- Coroutines タブには、実行中またはサスペンドされたコルーチンに関する情報が含まれています。
Debug ツールウィンドウで Resume Program をクリックしてデバッガーセッションを再開します。プログラムは同じブレークポイントで停止します。
これで Flow は2番目の値を発行します。
最適化により除外された変数
suspend
関数を使用している場合、デバッガーで変数の名前の隣に「was optimized out
」というテキストが表示されることがあります。
このテキストは、変数のライフタイムが短縮され、その変数がもはや存在しないことを意味します。 値が見えないため、最適化された変数を含むコードをデバッグするのは困難です。 -Xdebug
コンパイラオプションを使用すると、この動作を無効にできます。
本番環境ではこのフラグを絶対に使用しないでください :
-Xdebug
はメモリリークを引き起こす可能性があります。
並行して実行されるコルーチンを追加する
src/main/kotlin
にあるMain.kt
ファイルを開きます。エミッターとコレクターを並行して実行するようにコードを強化します。
- エミッターとコレクターを並行して実行するために、
buffer()
関数への呼び出しを追加します。buffer()
は発行された値を格納し、Flow コレクターを別のコルーチンで実行します。
kotlinfun main() = runBlocking<Unit> { simple() .buffer() .collect { value -> delay(300) println(value) } }
- エミッターとコレクターを並行して実行するために、
Build Project をクリックしてコードをビルドします。
2つのコルーチンで Kotlin Flow をデバッグする
println(value)
に新しいブレークポイントを設定します。画面上部の実行構成の隣にある Debug をクリックして、コードをデバッグモードで実行します。
Debug ツールウィンドウが表示されます。
Coroutines タブでは、2つのコルーチンが並行して実行されていることがわかります。
buffer()
関数により、Flow コレクターとエミッターは別のコルーチンで実行されます。buffer()
関数は Flow から発行された値をバッファリングします。 エミッターコルーチンは RUNNING ステータスになっており、コレクターコルーチンは SUSPENDED ステータスになっています。Debug ツールウィンドウで Resume Program をクリックして、デバッガーセッションを再開します。
これでコレクターコルーチンは RUNNING ステータスになり、一方エミッターコルーチンは SUSPENDED ステータスになっています。
各コルーチンをさらに詳しく調べて、コードをデバッグできます。