Introduction to Kotlin Flows and Channels
Tags: android, kotlin, beginners, jetpackcompose
Published: 2022-11-18 23:00:00

**Summarizing the behaviors of using Kotlin flows (cold stream) and Kotlin channels (hot stream)**

This is part of the asynchronous flow series:
- [Part 1 - Exploring Android LiveData Usages and Behaviors](https://vtsen.hashnode.dev/exploring-android-livedata-usages-and-behaviors)
- **Part 2 - Introduction to Kotlin Flows and Channels**
- [Part 3 - Exploring Different Ways to Collect Kotlin Flow](https://vtsen.hashnode.dev/exploring-different-ways-to-collect-kotlin-flow)
- [Part 4 - Convert Flow to SharedFlow and StateFlow](https://vtsen.hashnode.dev/convert-flow-to-sharedflow-and-stateflow)
- [Part 5 - Flow, SharedFlow, StateFlow Class Diagram](https://vtsen.hashnode.dev/flow-sharedflow-stateflow-class-diagram)
- [Part 6 - Kotlin Flow - Combine, Merge and Zip](https://vtsen.hashnode.dev/kotlin-flow-combine-merge-and-zip)    

Kotlin `Flow` is a cold stream, Kotlin `Channel` is a hot stream. The differences between hot and cold streams are summarized below.

## Cold Stream vs Hot Stream

| Behaviors | Cold Stream | Hot Stream |
| --- | --- | --- |
| Where data is produced? | Inside the stream | outside the stream |
| Unicast or multicast? | Unicast | Multicast | 
| Lazy or eager stream? | Lazy stream | Eager stream

**Terminology**
- **Unicast** - has only one subscriber per stream, new subscription creates new stream
- **Multicast** - has no or many subscribers per stream, new subscription uses existing stream
- **Lazy stream** - start emitting values only when someone start subscribing to it
- **Eager stream** - start emitting values even it does NOT have any subscribers

## Kotlin Flows

![Kotlin_Flows.drawio.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662029795523/gR8qVC37x.png)

`Flow` data is produced **inside the stream** by creating the `Flow` and calling the `FlowCollector<T>.emit()`. It is called upstream flow.

```kotlin
val flow: Flow<Int> = flow {
    repeat(10000) { value ->
        delay(1000)
        emit(value)
    }
}

```

However, the data won't be emitted until the `Flow<T>.collect()` is called. This is an example of collecting flow in `ViewModel`.  It is called downstream flow.


```kotlin
viewModelScope.launch {  
    flow.collect {  value ->
        /* collecting $value here */
    } 
}
```

Each time the `Flow<T>collect()` is called, a new cold stream is created. It is called **unicast**. Data is only emitting at this point - **lazy stream**. 

## Kotlin Channels

![Kotlin_Channels.drawio.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662202728915/h_19E8fRK.png)

`Channel` data is produced **outside the stream**.  Creating the channel and sending the data into the hot stream are separated. Sending data to the hot stream is called channel's sender. 

**Create the Channel**

```kotlin
private val channel = Channel<Int>()
```

**Send Data into the Hot Stream**
```kotlin
viewModelScope.launch {
    repeat(10000) { value ->
        delay(1000)
        channel.send(value)
    }
}

```

**Hot stream is like a buffer**, which has the buffer capacity. The default buffer capacity is zero. By default, when the buffer is overflow, the data sending is suspended until there is a receiver.

To receive the channel's data, you call the `Channel.receive()`. This is called the channel's receiver.

```kotlin
viewModelScope.launch {
    while(true) {
        val value = channel.receive()
    }
}
```

- Since the buffer capacity is zero by default, the buffer overflow happens as soon as you're sending the first data into the stream. Thus, the data sending is suspended after the first data until there is a receiver. This behavior looks very similar to lazy stream, but it is NOT. It is still an eager stream. 

- Imagine if the buffer capacity is more than zero, sending data occurs even without any receiver until the buffer is full. Thus, it is an **eager stream**.

Unlike `Flow`, having a new subscriber or new channel's receiver does not create a new stream. It still uses the existing stream. Thus, it is **multicast** stream.

> One thing I would like to emphasize is once the data is received, the data is removed from the hot stream / buffer. 

![Kotlin_Channels_2.drawio.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662205085170/tLBcsefvR.png)

Based on the diagram above, assuming there are already channel's receiver #1, #2 and #3 subscribing to the channel (calling the `Channel.receive()`function), the channel's sender is sending `1`, `2` and `3` to the hot stream. 
- Once `1` is received by receiver #1, receiver #2 and #3 won't receive `1` anymore. 
- Receiver #2 receives `2` instead, and receiver #3 receives `3`.
 
## Conclusion
I just summarize the behavior of using `Flow` and `Channel` at high-level. I do not really know any practical use of them, especially `Channel`. 

These are the notes that I have written down:
- `Flow` - store single value that changes over time
- `Channel` - store one-time event, collected by one observer?

`Flow` probably makes sense.  I have been using it to expose the data from a local database. But honestly, when do we use `Channel`? Snackbar?  If you have a good practical usage of it, please share that with me.

> **[Updated - Sept 23, 2022]:** After doing some research and found the following article by Google team which does NOT recommend `Channel` for a one-time event. In short, use everything with `StateFlow` - will be covered in the next article.

- [ViewModel: One-off event antipatterns](https://medium.com/androiddevelopers/viewmodel-one-off-event-antipatterns-16a1da869b95)

## Source Code
GitHub Repository: [Demo_AsyncFlow](https://github.com/vinchamp77/Demo_AsyncFlow) (see `FlowActivity` and `ChannelActivity`)

---

*Originally published at [https://vtsen.hashnode.dev](https://vtsen.hashnode.dev/introduction-to-kotlin-flows-and-channels)*.