In this tutorial you will learn about Flow and how to use in Kotlin android via simple step by step examples.

What is a Flow?

A flow is a type that can emit multiple values sequentially, as opposed to suspend functions that return only a single value.

For example,A good usage of a Flow for example is an app that needs to receive live updates from a database.

Flows are built on top of coroutines and can provide multiple values. A flow is conceptually a stream of data that can be computed asynchronously. The emitted values must be of the same type. For example, a Flow<Int> is a flow that emits integer values.

A flow is very similar to an Iterator that produces a sequence of values, but it uses suspend functions to produce and consume values asynchronously. This means, for example, that the flow can safely make a network request to produce the next value without blocking the main thread.

Kotlin Android Activity Lifecycle Example

Kotlin Android Activity Lifecycle E...
Kotlin Android Activity Lifecycle Example

There are three entities involved in streams of data:

  • A producer produces data that is added to the stream. Thanks to coroutines, flows can also produce data asynchronously.
  • (Optional) Intermediaries can modify each value emitted into the stream or the stream itself.
  • A consumer consumes the values from the stream.

Let’s look at some examples.

Example 1: Simple Kotlin Android Flow Example

A simple example to get you started with Flows. This example will teach you:

  • Flow
  • Kotlin Coroutines
  • Viewbinding

Step 1: Create Project

Start by creating an empty Android Studio project.

Step 2: Dependencies

Add the following statements in your app/build.gradle:

    // coroutines
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'

    // coroutine lifecycle scopes
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"

Step 3: Enable ViewBinding and Java8

Next enable Java8 and ViewBinding in your android{} closure:

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    buildFeatures {
        viewBinding true
    }

Step 4: Layout

Nothing special in our layout:

activiy_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Step 5: Our MainActivity

Go to your MainActivity.kt and add the following imports:

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import xyz.teamgravity.flow.databinding.ActivityMainBinding

Extend the AppCompatActivity and declare our ActivityMainBinding object:

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

In the onCreate() use the above ActivityMainBinding object to reference our layout:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

Now simulate getting work from the server as our background task:

        val flow = flow<Int> {
            for (i in 1..10) {
                emit(i)
                delay(1000L)
            }
        }

Then udpdate the UI:

        lifecycleScope.launch {
            // runs different coroutine from producer
            flow.buffer().filter {
                it % 2 == 0
            }.map {
                it * it
            }.collect {
                println("debug: $it")
                delay(2000L)
            }
        }
    }
}

Here’s the full code:

MainActivity.kt

package xyz.teamgravity.flow

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import xyz.teamgravity.flow.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // get data from imaginary server -> producer flow
        val flow = flow<Int> {
            for (i in 1..10) {
                emit(i)
                delay(1000L)
            }
        }

        // update ui when data ready -> consumer flow
        lifecycleScope.launch {
            // runs different coroutine from producer
            flow.buffer().filter {
                it % 2 == 0
            }.map {
                it * it
            }.collect {
                println("debug: $it")
                delay(2000L)
            }
        }
    }
}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

Number Link
1. Download Example
2. Follow code author