Reading — step 1 of 5
Learn
~1 min readCoroutines
Coroutines need ways to talk. Kotlin offers two:
Channel<T> — like a Go channel. Producers send, consumers receive:
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
val ch = Channel<Int>()
launch {
for (i in 1..5) ch.send(i * i)
ch.close()
}
for (sq in ch) {
println(sq)
}
}
for-in over a channel receives until close. Channels are lazy and one-shot — once consumed, the value is gone.
Flow<T> — cold async stream. Like a sequence but with suspend:
import kotlinx.coroutines.flow.*
fun squares(n: Int): Flow<Int> = flow {
for (i in 1..n) {
delay(10) // can suspend inside
emit(i * i)
}
}
fun main() = runBlocking {
squares(5).collect { value ->
println(value)
}
}
Cold = doesn't run until collected. Each collect re-runs the producer. Compare to channels which are hot.
Flow operators:
flow.map { it * 2 }
.filter { it > 5 }
.take(3)
.collect { println(it) }
flowOn(dispatcher) — change which thread the upstream runs on:
flow { ... }
.flowOn(Dispatchers.IO) // upstream on IO
.map { ... } // map on whatever collected with
.collect { ... }
StateFlow / SharedFlow — hot variants:
StateFlow<T>— reactive state holder, always has a valueSharedFlow<T>— multi-subscriber event stream
Used heavily in Android with Jetpack Compose / ViewModels.
Channels vs Flow:
- Channel — for hand-off between specific coroutines. Hot.
- Flow — for emission streams transformed with operators. Cold (or use Shared/StateFlow for hot).
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…