xref: /aosp_15_r20/external/kotlinx.coroutines/docs/topics/debug-flow-with-idea.md (revision 7a7160fed73afa6648ef8aa100d4a336fe921d9a)
1[//]: # (title: Debug Kotlin Flow using IntelliJ IDEA – tutorial)
2
3This tutorial demonstrates how to create Kotlin Flow and debug it using IntelliJ IDEA.
4
5The tutorial assumes you have prior knowledge of the [coroutines](coroutines-guide.md) and [Kotlin Flow](flow.md#flows) concepts.
6
7## Create a Kotlin flow
8
9Create a Kotlin [flow](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow.html) with a slow emitter and a slow collector:
10
111. Open a Kotlin project in IntelliJ IDEA. If you don't have a project, [create one](jvm-get-started.md#create-a-project).
122. To use the `kotlinx.coroutines` library in a Gradle project, add the following dependency to `build.gradle(.kts)`:
13
14   <tabs group="build-script">
15   <tab title="Kotlin" group-key="kotlin">
16
17   ```kotlin
18   dependencies {
19       implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:%coroutinesVersion%")
20   }
21   ```
22
23   </tab>
24   <tab title="Groovy" group-key="groovy">
25
26   ```groovy
27   dependencies {
28       implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:%coroutinesVersion%'
29   }
30   ```
31
32   </tab>
33   </tabs>
34
35   For other build systems, see instructions in the [`kotlinx.coroutines` README](https://github.com/Kotlin/kotlinx.coroutines#using-in-your-projects).
36
373. Open the `Main.kt` file in `src/main/kotlin`.
38
39    The `src` directory contains Kotlin source files and resources. The `Main.kt` file contains sample code that will print `Hello World!`.
40
414. Create the `simple()` function that returns a flow of three numbers:
42
43    * Use the [`delay()`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html) function to imitate CPU-consuming blocking code. It suspends the coroutine for 100 ms without blocking the thread.
44    * Produce the values in the `for` loop using the [`emit()`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow-collector/emit.html) function.
45
46    ```kotlin
47    import kotlinx.coroutines.*
48    import kotlinx.coroutines.flow.*
49    import kotlin.system.*
50
51    fun simple(): Flow<Int> = flow {
52        for (i in 1..3) {
53            delay(100)
54            emit(i)
55        }
56    }
57    ```
58
595. Change the code in the `main()` function:
60
61    * Use the [`runBlocking()`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html) block to wrap a coroutine.
62    * Collect the emitted values using the [`collect()`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/collect.html) function.
63    * Use the [`delay()`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html) function to imitate CPU-consuming code. It suspends the coroutine for 300 ms without blocking the thread.
64    * Print the collected value from the flow using the [`println()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/println.html) function.
65
66    ```kotlin
67    fun main() = runBlocking {
68        simple()
69            .collect { value ->
70                delay(300)
71                println(value)
72            }
73    }
74    ```
75
766. Build the code by clicking **Build Project**.
77
78    ![Build an application](flow-build-project.png)
79
80## Debug the coroutine
81
821. Set a breakpoint at the line where the `emit()` function is called:
83
84    ![Build a console application](flow-breakpoint.png)
85
862. Run the code in debug mode by clicking **Debug** next to the run configuration at the top of the screen.
87
88    ![Build a console application](flow-debug-project.png)
89
90    The **Debug** tool window appears:
91    * The **Frames** tab contains the call stack.
92    * The **Variables** tab contains variables in the current context. It tells us that the flow is emitting the first value.
93    * The **Coroutines** tab contains information on running or suspended coroutines.
94
95    ![Debug the coroutine](flow-debug-1.png)
96
973. Resume the debugger session by clicking **Resume Program** in the **Debug** tool window. The program stops at the same breakpoint.
98
99    ![Debug the coroutine](flow-resume-debug.png)
100
101    Now the flow emits the second value.
102
103    ![Debug the coroutine](flow-debug-2.png)
104
105### Optimized-out variables
106
107If you use `suspend` functions, in the debugger, you might see the "was optimized out" text next to a variable's name:
108
109![Variable "a" was optimized out](variable-optimised-out.png)
110
111This text means that the variable's lifetime was decreased, and the variable doesn't exist anymore.
112It is difficult to debug code with optimized variables because you don't see their values.
113You can disable this behavior with the `-Xdebug` compiler option.
114
115> __Never use this flag in production__: `-Xdebug` can [cause memory leaks](https://youtrack.jetbrains.com/issue/KT-48678/Coroutine-debugger-disable-was-optimised-out-compiler-feature#focus=Comments-27-6015585.0-0).
116>
117{type="warning"}
118
119## Add a concurrently running coroutine
120
1211. Open the `Main.kt` file in `src/main/kotlin`.
122
1232. Enhance the code to run the emitter and collector concurrently:
124
125    * Add a call to the [`buffer()`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/buffer.html) function to run the emitter and collector concurrently. `buffer()` stores emitted values and runs the flow collector in a separate coroutine.
126
127    ```kotlin
128    fun main() = runBlocking<Unit> {
129        simple()
130            .buffer()
131            .collect { value ->
132                delay(300)
133                println(value)
134            }
135    }
136    ```
137
1383. Build the code by clicking **Build Project**.
139
140## Debug a Kotlin flow with two coroutines
141
1421. Set a new breakpoint at `println(value)`.
143
1442. Run the code in debug mode by clicking **Debug** next to the run configuration at the top of the screen.
145
146    ![Build a console application](flow-debug-3.png)
147
148    The **Debug** tool window appears.
149
150    In the **Coroutines** tab, you can see that there are two coroutines running concurrently. The flow collector and emitter run in separate coroutines because of the `buffer()` function.
151    The `buffer()` function buffers emitted values from the flow.
152    The emitter coroutine has the **RUNNING** status, and the collector coroutine has the **SUSPENDED** status.
153
1543. Resume the debugger session by clicking **Resume Program** in the **Debug** tool window.
155
156    ![Debugging coroutines](flow-debug-4.png)
157
158    Now the collector coroutine has the **RUNNING** status, while the emitter coroutine has the **SUSPENDED** status.
159
160    You can dig deeper into each coroutine to debug your code.
161