Kotlin Flow for Android: Getting Started

In this tutorial, you’ll learn about the basics of Kotlin Flow, and you’ll build an Android app that fetches weather forecast data using Flow. By Dean Djermanović.

4.8 (35) · 2 Reviews

Download materials
Save for later
Share

Kotlin Flow is a new stream processing API developed by JetBrains, the company behind the Kotlin language. It’s an implementation of the Reactive Stream specification, an initiative whose goal is to provide a standard for asynchronous stream processing. Jetbrains built Kotlin Flow on top of Kotlin Coroutines.

By using Flow to handle streams of values, you can transform data in complex multi-threaded ways, by writing just a small bit of code!

In this tutorial, you’ll have a chance to play with several different approaches to handling collections, and you’ll explore the capabilities of Kotlin Flow by building a simple weather app. In the process, you’ll learn about:

  • Data collections and streams.
  • Synchronous and asynchronous API calls.
  • Hot and cold data streams.
  • Exception handling during flow processing.

You must also have a basic understanding of Kotlin Coroutines to follow along with this tutorial. You can check out these tutorials to familiarize yourself with Coroutines:

The sample app in this tutorial uses the MVVM architectural pattern. MVVM stands for Model-View-ViewModel and represents a pattern where you update the user interface through reactive streams of data. If you’re not familiar with this pattern, please check out our MVVM on Android video course to familiarize yourself with it.

Note: This tutorial assumes you have a solid knowledge of Android development. If you’re completely new to the topic, please check out our Beginning Android Development with Kotlin series first.

Getting Started

In the first part of the tutorial, you’ll learn about Kotlin Flow concepts, using the Kotlin Playground app as a… well, a playground! You’ll then use what you’ve learned to develop a more robust Android app that displays data retrieved via API calls.

Download the materials for this tutorial using the Download Materials button at the top or bottom of the page. For now, open the Playground-Starter project in Android Studio. This is just an empty project that will serve as a playground.

Returning Multiple Values

You probably know that suspending functions can return a single value asynchronously. When using suspending functions, you don’t have to worry about threading, the Coroutines API does that for you!

Flow, however, can return multiple values asynchronously, and over time. Asynchronous operations are operations you need to wait on, such as network requests. You never know how long these operations might take! They can take anywhere from a couple of milliseconds to several seconds to get a response. Any long-running operation should be asynchronous because actively waiting for them can freeze your programs.

You’ll see how returning values using suspending functions is very much different from the Flow API, with a few examples!

List

Open main.kt file, and add the following function:

suspend fun getValues(): List<Int> {
  delay(1000)
  return listOf(1, 2, 3)
}

This function computes values and adds those values into a List. delay() simulates a long-running operation, like you would have using a remote API.

Now add a function to process these values:

fun processValues() {
  runBlocking {
    val values = getValues()
    for (value in values) {
      println(value)
    }
  }
}

Call processValues() from main():

fun main() {
  processValues()
}

Build and run the code, using the green “play” icon next to the main function. You’ll get this output after a delay of one second:

1
2
3

When you call getValues(), it returns a List with three values. You then use those values in processValues(). Within a for loop, you iterate over the List and print out the values.

A visual representation of the function is the following:

List Diagram

This is fine for three values. But not if it takes a lot of time to compute these values. In that case, you’d have to wait for all of the values to be computed. If each value takes a second, you would wait hours for thousands of values!

It’s very inefficient as it adds extra delay to data processing. Ideally, you want to start processing each list item as soon as it becomes available. Sequences allow you to do this.

Sequence

Sequences are very similar to lists. But unlike lists, they are lazily evaluated. This means they produce values as you iterate over them, instead of producing them all at once. Refactor getValues() to return a Sequence:

suspend fun getValues(): Sequence<Int> = sequence {
  Thread.sleep(250)
  yield(1)
  Thread.sleep(250)
  yield(2)
  Thread.sleep(250)
  yield(3)
}

Thread.sleep(250) simulates a delay when computing each value.

Build and run the project. You’ll get the same output as before, but this time you won’t have to wait for all the values. You’ll produce and consume them, one at a time:

1
2
3

Now, instead of waiting for all of the items, processValues() consumes each item as getValues() produces it.

Sequences use Iterators under the hood and block while waiting for the next item. This works when returning a simple list, but what if your application needs to communicate with a streaming API?

Channel

Streaming APIs are almost the exact opposite of REST APIs. When communicating with a REST API, you make a request and the API sends a response. A streaming API works differently. It connects to a client and continuously listens to new information, over time. Twitter, for example, provides a streaming API that you can use to stream tweets in real time.

You can use Sequences for synchronous streams. But you need a different solution for asynchronous streams.

For asynchronous streams, you could use Channels from Kotlin Coroutines. Conceptually, you can think of channels as pipes. You send items through one pipe and receive a response through the other. However, a channel represents a hot stream of values. Once again, hot streams start producing values immediately.

And this introduces another set of challenges.

Hot Versus Cold Streams

A channel, which is a hot stream, will produce values even if aren’t listening to them on the other side. And if you are not listening to the stream, you are losing values.

In the following diagram, getValues() emits the items via a channel. processValues() receives 1, 2, 3, and then it stops listening for items. The channel is still producing the items, even when no one is listening:

Sequence Diagram

In practice, you can use a channel to have an open network connection. But that can lead to memory leaks. Or you could forget to subscribe to a channel, and “lose” values.

Hot streams push values even when there is no one consuming them. However, cold streams, start pushing values only when you start collecting!

And Kotlin Flow is an implementation of cold streams, powered by Kotlin Coroutines!