Sign in
Log inSign up
Kotlin Flow Basics

Kotlin Flow Basics

Whats a Kotlin Flow🧐?

kevin kenei's photo
kevin kenei
·Dec 14, 2021·

4 min read

Think of Kotlin Flows as a way of being notified of your code changes and send them through a pipeline of actions that you can potentially modify .

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!

We have two types of streams, a cold and a hot stream. A cold stream does not start producing values as long as there are no functions or scopes that collect values from a flow, While a hot stream on the other hand starts producing values immediately.Kotlin Flow is a type of cold stream

Kotlin flow consists of a producers and a consumers. Producers emit data to the flow while consumers collect data from the flow.

Basically a Flow is a coroutine that is able to emit multiple values over a period of time.

A single suspend function can only return a single value so if you have it in a function, you will have that single return statement when called and if your code reaches that point then your code is over.

However if you want to do something like a countdown timer that emits a value every second you can't achieve that with a normal coroutine, as🤷‍♂️🤷‍♂️ how are you going to be notified about a value every single second? That is where coroutine flow come into play.

In this tutorial, we will explore the capabilities of Kotlin Flow by building a very simple countdown timer:

Step 1 — Project Set Up🛠️

Create a new project in Android studio and 0pen the build.gradle file and add the following viewmodel and coroutines dependencies.

implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.1"

Step 2 — Creating a Producer🧑🏽‍🌾

As we said the producer emits data to the flow how do we create a producer? Create our a new file called MainViewModel which will containt our flow logic

Class MainViewModel : ViewModel(){}

In our MainViewModel add this code.

class MainViewModel: ViewModel() {

val countDownFlow = flow<Int>{
    val startingValue = 10
    var currentValue = startingValue
    emit(startingValue)
    while (currentValue > 0){
        delay(1000L)
        currentValue--
        emit(currentValue)
    }
}

In which we create a flow called countDownFlow that that emits intergers. The flow first emits the startingValue of 10 before checking if currentValue is greater than 0 in which it starts the countdown by delaying for a second before reducing the current value ( currentValue--) and emiting the updated currentValue.

Step 3 — Creating a Consumer 😋

To create a flow, we need a consumer. As we mentioned earlier, a consumer collect data from the flow. Now we can jump to our MainActivity to see how this can be shown in our UI .We will be using a simple compose text to show our results. In your MainActivity add this code.

   class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
            val viewModel = viewModel<MainViewModel>()
            val time = viewModel.countDownFlow.collectAsState(initial = 10)

              Box(modifier = Modifier.fillMaxSize()){
                  Text(
                      text = time.value.toString(),
                      fontSize = 30.sp,
                      modifier = Modifier.align(Alignment.Center))
              }
    }}

}

Here we first get the reference to our MainViewModel, then we can now get our flow as state in our MainActivity and set its inital value to 10.When we now launch our app we we can see our countdown works

      val time = viewModel.countDownFlow.collectAsState(initial = 10)

Our time variable changes everytime our countdown flow actually counts down.

Step 4 — Using the ViewModel 📑

Often you want to be notified of changes of a flow but not in our Ui Layer, Lets see how we can achieve this in our ViewModel by adding this function to our ViewModel

private fun collectFlow(){
       viewModelScope.launch {
           countDownFlow.collect { time->
               delay(1500L)
               println("The current time is $time")
           }
       }
      }

Here we create function collectFlow that collects our Flow. Since collecting our Flow is a suspend action we execute it in a coroutine by calling it inside a viewModelScope. Here we can now get the time value everytime we call emit in our flow. Lets now make sure to call the function by adding it in an init block above it.

   init {
    collectFlow()
}

When we now launch our app and see our Log Cat we can now see we are able to collect flows in our ViewModel.

curent.png

Conclusion

Hopefully you now have an understanding of flow basics how to use flow consumers and producers. If you want to explore this Kotlin Flows further and get deeper into functional programming, please check their . documentation

You can also take a look at the code in this . repository

Happy coding!