Useful for streams of data, flow is a type that can emit multiple values sequentially. Flow is similar to an Iterator but since its built on top of coroutines it can emit values asynchronously hence flow is perfect for making network calls or doing expensive computations asynchronously without blocking the main thread.

Keywords

  • Flow - a type that can emit multiple values sequentially and asynchronously
  • collect - a suspend function that can trigger a flow collection, it needs to be launched from a coroutine scope , new values will be emitted until there are no more value to be emitted
  • emit(value) - emits an item to the flow
  • close(throwable) closes a flow
  • callbackFlow{} - builder function to convert a callback based APIs into flow
  • offer() - used along with callbackFlow to emit items to a flow
  • awaitClose{} - used along with callbackFlow will keep the flow open until its closed or cancelled.

Producers

  • Produces data that is emitted to the stream, using coroutines producers can able to emit asynchronously. eg repository or view in case of emitting UI events.
  • Use the builder function flow {} to create a producer, use emit(value) to emit values from a producer.
  • Producers cannot emit values from a different CoroutineContext.
  • A producer will be cancelled either when the producer finishes and stop emitting values or the coroutine that collects is cancelled.
  • Use a callbackFlow builder function to convert a callback to flow, unlike flow the callbackFlow builder allows to emit values form another coroutine context.

Consumers

  • Consumes value from the stream eg viewModel or view.
  • Flows are cold and lazy and are executed each time and only when collect or some other terminal operator is called.
  • Use the intermediary operator catch to handle exceptions from a producer. catch can also catch the exception and emit another value.

Intermediary operators

  • We can use intermediate operators to transform the data in between the producers and consumers without consuming the values. eg map onEach
  • Applying an intermediate operator will not start flow collection from a producer. You need to call a terminal operator like collect to start the flow.
  • Intermediate operators can be chained one after the other eg .map{}.onEach{}

Some popular intermediate operators

  • map
  • filter
  • onEach
  • catch

Tips

  • use delay(time) to suspend a coroutine for some time.

Resources