Blog Infos
Author
Published
Topics
, , , ,
Published
Photo by Marc Reichelt on Unsplash

 

Flow is used to stream data asynchronously. That means flow will send a sequence of data asynchronously and associated collectors will receive the data.

According to the official documentation of Flow,

Flow is an asynchronous data stream that sequentially emits values and completes normally or with an exception.

We can see Flow is divided into two types: Cold Flow and Hot Flow. Many developers, including me, are confused about these two types of flows. Here, I will try to clarify the concept of these two types of flows simply.

Prerequisite:
We need to have a basic idea of Kotlin Coroutine and the basic idea of Flow to understand the difference between Cold Flow and Hot Flow.

Dependecies for Android:

implementation ("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
implementation ("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version")
Cold Flow:
  • Cold flow can send data to only one collector.
  • It doesn’t store data. For whom the flow will store data? Where the collector is only one.
  • When a new collector is registered, Flow starts its job from the beginning.

Let’s understand this through an example:

val flow = flow<Int> { // flow builder
    // A dummy operation
    (1..5).forEach {
        delay(1000)
        emit(it)
    }
}

Here, a cold flow is defined as a dummy operation.

val flow = flow<Int> { // flow builder
    // A dummy operation
    (1..5).forEach {
        delay(1000)
        emit(it)
    }
}

val coroutineScope = CoroutineScope(Dispatchers.Default)
coroutineScope.launch {
  flow.collect {
      println("First collector: $it")
  }
}

A collector is added for the defined flow. When the collector is added, the defined dummy operation in the flow builder is triggered. We can name this collector “First Collector”. After running the program the output is added below.

Output:

First collector: 1
First collector: 2
First collector: 3
First collector: 4
First collector: 5

Now, we will see what happens if one more collector is added after three seconds. We can name this collector the “Second collector.”

val flow = flow<Int> { // flow builder
    // A dummy operation
    (1..5).forEach {
        delay(1000)
        emit(it)
    }
}

val coroutineScope = CoroutineScope(Dispatchers.Default)
coroutineScope.launch {
  flow.collect {
      println("First collector: $it")
  }
}

delay(3000)
println("3 SECONDS PASSED")

coroutineScope.launch {
  flow.collect {
      println("Second collector: $it")
  }
}

Output:

First collector: 1
First collector: 2
3 SECONDS PASSED
First collector: 3
Second collector: 1
First collector: 4
First collector: 5
Second collector: 2
Second collector: 3
Second collector: 4
Second collector: 5

Here, we can see that after three seconds, when the second collector is added, it prints the value of 1, whereas the first collector prints 3. That means that adding a new collector has invoked the execution of the defined operation from the beginning.

So, We understood that a running operation of a cold flow can’t communicate with any other collector. It works for only one collector without storing any data. When a new collector is added, execution of the defined operation is started from the beginning.

Hot flow:
  • Hot flow can send data to multiple collectors.
  • It can store data. It can provide stored data to newly added collectors.
  • When a new collector is registered, unlike cold flow, it doesn’t start the job from the beginning. Let’s see the example:
val sharedFlow = MutableSharedFlow<Int>()

coroutineScope.launch {
   (1..5).forEach {
       delay(1000)
       sharedFlow.emit(it)
   }
}

Here, a SharedFlow is defined. SharedFlow is a flow that has characteristics of hot flow.

val sharedFlow = MutableSharedFlow<Int>()

coroutineScope.launch {
   (1..5).forEach {
       delay(1000)
       sharedFlow.emit(it)
   }
}

coroutineScope.launch {
  sharedFlow.collect {
      println("First collector: $it")
  }
}

Here, the first collector is launched for the SharedFlow.

Output:

First collector: 1
First collector: 2
First collector: 3
First collector: 4
First collector: 5

At this stage, when a single collector is added behavior is the same as like as cold flow.

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

,

Tests unitaires avec KotlinFlow

Lorsque nous développons une fonctionnalité, nous devons écrire les tests unitaires. C’est une partie essentielle du développement. Cela assure le bon fonctionnement du code lors de futurs changements ou refactorisations. Kotlin Flow ne fait pas…
Watch Video

Tests unitaires avec KotlinFlow

Florent Blot
Android Developer
Geev

Tests unitaires avec KotlinFlow

Florent Blot
Android Developer
Geev

Tests unitaires avec KotlinFlow

Florent Blot
Android Developer
Geev

Jobs

Let’s add the second collector after three seconds of adding the first collector.

val sharedFlow = MutableSharedFlow<Int>()

coroutineScope.launch {
   (1..5).forEach {
       delay(1000)
       sharedFlow.emit(it)
   }
}

coroutineScope.launch {
  sharedFlow.collect {
      println("First collector: $it")
  }
}

delay(3000)
println("3 seconds delay passed")

coroutineScope.launch {
  sharedFlow.collect {
      println("Second collector: $it")
  }
}

The second collector is added with a three second delay.

Now let’s see the output:

First collector: 1
First collector: 2
3 seconds delay passed
Second collector: 3
First collector: 3
Second collector: 4
First collector: 4
Second collector: 5
First collector: 5

Here, We can notice after three seconds when the second collector is added, both the first and second collectors have printed 3. Here, Unlike Cold Flow, the Second Collector didn’t receive the value from the beginning of the execution. It received the value from the current position of the execution. Actually, this current value was stored in the flow and passed to the newly added collector.

Conclusion: We understood the main difference between cold flow and hot flow. When a new collector is registered to a cold flow, it launches the execution of the defined operation from the beginning, so the collector also receives the value from the beginning.

For hot flow, when a new collector is registered, It doesn’t launch any new execution of the flow, cold flow sends value from the current position of the flow to the new collector.

Bonus: We can configure the number of stored data by passing the value of the replay parameter.

val sharedFlow = MutableSharedFlow<Int>(replay = 2)

This article is previously published on proandroiddev.com

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
It’s one of the common UX across apps to provide swipe to dismiss so…
READ MORE
blog
Hi, today I come to you with a quick tip on how to update…
READ MORE
blog
Automation is a key point of Software Testing once it make possible to reproduce…
READ MORE
blog
Drag and Drop reordering in Recyclerview can be achieved with ItemTouchHelper (checkout implementation reference).…
READ MORE
Menu