Flow basics.
Suspend functions return a single value. But what if you need to return multiple values over time? Flow is Kotlin's solution for asynchronous streams. Today we learn the fundamentals of Flow.
Sometimes one value is not enough.
A function that fetches a single user returns User. But what about a function that fetches users as they arrive? One at a time, over time?
You could return a list. But then you wait for all values. What if you want to process each as it comes?
You need a stream. A sequence of values emitted over time. Process each value as it arrives. Do not wait for all.
Sequences give you multiple values lazily. But they are synchronous. Flow gives you multiple values asynchronously.
Flow is a cold asynchronous stream.
It represents a sequence of values that are computed asynchronously. Values are emitted one at a time, over time.
Flow is cold. It does not do anything until you collect it. Each collector gets its own stream of values.
Think of Flow as an asynchronous sequence. Like Sequence, it is lazy. Unlike Sequence, it can suspend.
Flow works with coroutines. Emissions can suspend. Collection can suspend. Everything is non-blocking.
A cold stream starts fresh for each collector.
When you collect a Flow, it runs from the beginning. Another collector gets another run. No shared state.
Cold streams are like functions. Call the function, get a result. Call again, get another result. Each call is independent.
A hot stream runs whether anyone collects or not.
Channels are hot. They produce values regardless of receivers. If no one receives, values might be lost.
Flow is cold. It waits for collection. No wasted computation. No lost values.
Use the flow builder to create a Flow.
flow brace emit 1 emit 2 emit 3 close brace. This creates a Flow that emits three integers.
Inside the flow block, call emit to send values. emit is a suspend function. You can call other suspend functions too.
val numbers equals flow of Int brace body close brace. The flow builder returns Flow of T.
The code inside flow runs when collected. It does not run when you create the Flow. Creation is instant. Execution is on collection.
collect starts the flow and receives values.
flow dot collect brace value arrow process value close brace. For each emitted value, the lambda runs.
collect is a suspend function. It suspends until the flow completes.
collect is a terminal operator. It ends the flow pipeline and triggers execution.
Each collect is independent. Collect twice, the flow runs twice. Cold behavior.
The collector receives values in order. First emission arrives first. Sequential.
By default, flow execution is sequential.
One coroutine emits and collects. The emitter emits a value, the collector processes it, then the next emission happens.
emit suspends until the collector finishes processing. This is backpressure. The producer waits for the consumer.
You do not need to worry about thread safety. Sequential execution means no concurrent access.
If you want concurrency, you explicitly use operators like buffer or flatMapMerge. But default is simple and safe.
Consider fetching pages of data.
A flow emits each page as it loads. The collector processes each page immediately. No waiting for all pages.
flow brace for page in 1 to totalPages emit fetchPage of page close brace.
The collector receives pages one by one. It can display each as it arrives. User sees progress immediately.
If the collector cancels, the flow stops fetching. No wasted network calls. Cancellation works naturally.
Several functions create flows from existing data.
flowOf 1 comma 2 comma 3 creates a flow of fixed values.
list dot asFlow converts a collection to a flow.
sequence dot asFlow converts a sequence to a flow.
These are convenience builders. They wrap existing data in flow semantics.
Use them when you have data and want flow operators. Transform, filter, then collect.
Let us summarize.
Flow is a cold asynchronous stream of values.
Cold means it runs fresh for each collector. No shared state, no lost values.
Create flows with the flow builder and emit values inside.
Collect flows to receive values. collect is a terminal operator.
Flow is sequential by default. Simple and safe.
Flow extends coroutines to handle multiple async values elegantly.