Kotlin Flows and LiveData

Begum Avci Kocaman
Huawei Developers
Published in
6 min readSep 27, 2023
Kotlin Flows and LiveData

Introduction

Hello everyone, in this article I will give information about how we can write code using flows, stateflow, sharedflow and live data, and their similar and different features.

Flow

Kotlin Flows is a library that supports reactive programming paradigms, offered as part of the Kotlin programming language. Flows are used for asynchronous programming and are specifically available for data analysis.

Here are the basic concepts and features of Kotlin Flows:

  1. Asynchronous Programming: Kotlin Flows focuses on asynchronous programming. This allows you to continue other processes without blocking long-running processes. It is especially important when interacting with processes running in the background.
  2. Stream Processing: Kotlin Flows represent streams of data. This allows a series of values ​​to be produced and consumed sequentially. For example, reading line by line from a file can represent a data stream.
  3. Cold Streams: Cold streams mean that a stream will start over every time it is subscribed. That is, data generation starts again every time there is a subscription.
  4. Hot Streams: Hot streams do not keep track of when a stream starts and ends. The initiation and termination of the flow depend on external factors.
    Producer and Consumer: A Flow can have a producer and one or more consumers. The producer produces data and the consumer receives and processes this data. This allows multiple subscriptions.
  5. Flow Processing Operators: Kotlin Flows provides a set of operators. These operators are used to process and transform data streams. For example, there are operators such as map, filter, transform, and collect.
  6. Integration with Coroutines: Kotlin Flows works integrated with coroutines. This allows streams to easily handle asynchronous operations. Additionally, flows work with routines to make operations more efficient.
  7. Freezable (Suspending) Functions: Flows work with freezable functions. This allows the stream to wait while starting and waiting for long-running processes.

To create an example Flow, you can use the flow { … } structure. You can also convert existing collections or arrays into a Flow with .asFlow(). For example, if you want to create a Flow to read line by line from a file:

This creates a function that returns a Flow. This Flow will start over every time it subscribes and sends each row from the file.

Kotlin Flows is a very powerful tool when working with asynchronous programming and data flows. It is used in scenarios such as long-running processes, network requests, and database operations.

flow entities

State Flow

Kotlin StateFlow is one of Kotlin’s reactive programming libraries. StateFlow is used to observe a changing value and broadcasts that value as a stream. StateFlow is used specifically to manage UI states.

Here are the basic concepts and features of Kotlin StateFlow:
1. Fluid State: StateFlow represents a fluid state. This may change over time and ensures that these changes are communicated to subscribers.

2. Mutable and Immutable: StateFlow offers two types: mutableStateOf and stateIn. You can change the state with mutableStateOf, but not with stateIn. 3. Asynchronous Changes: StateFlow is used to change the value and notify subscribers of this change. Whenever the value changes, the new value is sent to subscribers.
4. Difference Between Flow and StateFlow: StateFlow is a flow, but its difference is that it represents a value and sends notifications to subscribers when this value changes. That is, StateFlow is used for a single value, while Flow represents multiple values.
5. Lifecycle Awareness: StateFlow knows the lifecycle and prevents leaks if handled properly.
6. Subscription and Cancellation: StateFlow sends the value immediately when you subscribe. When you end the subscription, value changes are no longer received.

An example of Kotlin StateFlow usage is shown below:

In the example above, the CounterViewModel class creates a MutableStateFlow named _counter. This converts _counter into an immutable StateFlow named counter. The increment() function takes the current value of _counter, adds 1, and reflects this value back to _counter, causing the state to change.
Use of:

The above code creates the CounterViewModel and observes the counter. When increment() is called twice, the value is incremented by 1 and this value is passed to the observer (collect). This is useful for managing UI states or keeping track of any variable states.

Shared Flow

Here are the key features of SharedFlow:
1. Multiple Subscribers: SharedFlow allows multiple subscribers to receive the same values.
2. Keeping Published Values ​​in Memory: SharedFlow stores the values ​​in memory after publishing them. A new observer who subscribes immediately receives the last published value.
3. Hot Flow: SharedFlow is a type of “hot” flow, meaning it can generate values ​​even before the subscription state starts.
4. Lifecycle Awareness: SharedFlow knows the lifecycle and prevents leaks if handled properly.
5. Temperature and Coldness: SharedFlow may also publish values ​​before the subscription begins. This means SharedFlow is a “hot” flow. “Cold” flows, on the other hand, publish values ​​after the subscription has started.

An example of Kotlin SharedFlow usage is shown below:

In the above example, we created a sharedFlow with MutableSharedFlow. Next, we created two different subscribers (job1 and job2) in two separate threads (coroutines). Both subscribers receive the same values.

Afterward, the values ​​are published via the emit method via sharedFlow. Both subscribers receive the published values ​​immediately.
This example shows that SharedFlow ensures that the same values ​​are received by multiple subscribers.

LiveData

Kotlin LiveData is a lifecycle-aware data holder class used in Android applications. LiveData acts as a bridge between components that listen for data changes and automatically react to those changes. In this way, communication between the UI (User Interface) and the data source (for example, database or network service) becomes more streamlined and error-free.

Here are the key features of LiveData:
1. Lifecycle Awareness: LiveData automatically tracks the lifecycle of Android components (Activity, Fragment). This way, if a component is inactive, data updates are not received.
2. UI Updates: LiveData automatically updates the UI when data changes. This makes it easier to work without having to listen to the data source and manually update the UI with every change.
3. Data Retention Ability: LiveData retains data and is passed to UI components only in the relevant lifecycle state.
4. Error Management: LiveData can also manage error conditions. For example, when a network request fails, it forwards the error to listening components.
5. Better Memory Management: LiveData is optimized for application memory management. This allows the application to have lower memory consumption.
6. Integration with Flow: LiveData can integrate with Kotlin’s Flow API, so it is possible to listen to and process data as it flows.

An example of Kotlin LiveData usage is as follows:

In the example above, we created a liveData with MutableLiveData. We created an Observer and this observer listens for every change in LiveData. When the value of LiveData changes, observer is called automatically.

Finally, we removed the observer with the removeObserver method. This stops LiveData from being listened to by a specific lifecycle owner.

In conclusion;

They show similar features in terms of asynchronous, reactive programming and lifecycle. For flow, the Kotlin standard library stands out with its multiple values ​​and cold flow features. For shared flow, the Kotlin coroutines library differs from flow with its multiple jobs and hot flow features. In state flow, the Kotlin coroutines library is also like shared flow. The difference here is state, mutable, and immutable features, while Livedata provides advantages in terms of Android Architecture Components, UI updates, error management, and better memory management.

References:

--

--