3 reasons why I'm not migrating LiveData to StateFlow
Tags: android, jetpack, kotlin, coroutines
Published: 2022-08-21 14:40:29

---
title: 3 reasons why I'm not migrating LiveData to StateFlow
published: true
description: LiveData is not deprecated
tags: #android #jetpack #kotlin #coroutines
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f9yodmng02fawp97dzwz.jpg
# Use a ratio of 100:42 for best results.
---

I have a confession to make, after reading through [StateFlow and SharedFlow documentation](https://developer.android.com/kotlin/flow/stateflow-and-sharedflow), watching [Android Developers's video](https://www.youtube.com/watch?v=fSB6_KE95bU), and reviewing [nowinandroid](https://github.com/android/nowinandroid) source codes, I'm not convinced to migrate LiveData to StateFlow or SharedFlow. At least for now. Here's why:

## 1. Most of the time, I only do one-shot operation

According to [Kotlin documentation](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/) flow is "An asynchronous data stream that sequentially emits values and completes normally or with an exception."

There are valid use-cases for using flow, like fetching the latest data from server **periodically** or receiving **live-update** of query result when using Room.

But, most of the time, I only need to do a **one-shot task**. Not more, not less. Such as, making a GET request to a server and retrieving a value from a database. In those situations, the nature of my task is not stream. Even though I can convert it to flow:

```kotlin
flow {
	val weather = weatherApi.getWeather(coordinate)
	emit(weather)
}
```

This works, yet in my opinion, I added an extra line of codes for no specific reason.

We can also create a StateFlow or SharedFlow without flow.

```kotlin
private val _myState = MutableStateFlow(
    MyState(
    	title = R.string.title,
    	index = 0,
    )
)
val myState: StateFlow<MyState> = _myState.asStateFlow()
```

But again, if it's not emitting multiple values sequentially, why should I add more code?

This brings us to my second reason.

## 2. LiveData is lifecycle-aware

StateFlow and SharedFlow are part of Kotlin library. It's designed to be platform agnostic (go KMM! 🚀), so it doesn't know about Android framework and its lifecycle. If you want to integrate it Android, you need to ensure it follows Android lifecycle.

```kotlin
// Activity

lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.uiState.collect { uiState ->
            when (uiState) {
                is UiState.Success -> showSuccess(uiState.data)
                is UiState.Error -> showError(uiState.exception)
            }
        }
    }
}
```

If only there is a Jetpack library for that.. 🤔

That's what LiveData is made for! Taken from [Android documentation](https://developer.android.com/topic/libraries/architecture/livedata), "LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services.".

The same functionality can be achieved with this code.


```kotlin
// Activity

viewModel.uiState.observe(this) { uiState ->
	is UiState.Success -> showSuccess(uiState.data)
    is UiState.Error -> showError(uiState.exception)
}
```

By using LiveData, we don't need to manually handle the lifecycle, worry about memory leaks, and be sure that the data is always up-to-date.

One caveat, I realize in Compose the difference isn't significant (Kudos to Jetpack team 👏). 

```kotlin
@Composable
fun HomeRoute(
    modifier: Modifier = Modifier,
    viewModel: MyViewModel = getViewModel<MyViewModel>()
) {
    val uiStateLiveData by viewModel.uiState.observeAsState(initial = UiState.Loading)
    val uiStateStateFlow by viewModel.uiState.collectAsStateWithLifecycle()
}
```

The stable version of [Jetpack Compose is just released](https://android-developers.googleblog.com/2021/07/jetpack-compose-announcement.html) last year. While [I do like writing UI using Compose](https://github.com/aldoKelvianto/Mona-Android-App), I think most companies still need more time to adopt Compose.


## 3. I don't need StateFlow or SharedFlow features

StateFlow and SharedFlow have many features for configuring the emitted elements. SharedFlow has a reply functionality that can resend previously-emitted values for new subscribers. StateFlow has a time-out mechanism before stopping upstream flow using `WhileSubscribed` class.

```kotlin
val uiState: StateFlow<UiState> = flow {
    emit(repository.getItem())
}.stateIn(
    scope = viewModelScope, 
    initialValue = UiState.Loading,
    started = WhileSubscribed(5_000),
)
```

flow also allows you to combine multiple flows into a StateFlow.

```kotlin
val uiState: StateFlow<UiState> = combine(
    userRepository.getUser(),
    weatherRepository.getWeather(),
    statusRepository.getStatusStream(),
) { user, weather, status stream -> {
    // ...
}
```

Whereas, in my projects, the cool features that SharedFlow and StateFlow provides is a nice-to-have, not a must-have. The complex operation is handled on different classes, like on `Repository` (data layer) or `UseCases` (domain layer).

For merging multiple data-sources, like network and database, I can use `Repository` backed with `NetworkDataSources` and `DbDataSources`. For data manipulation, Kotlin's collection has many useful functions (map, reduce, groupBy, count, etc.). If I want to ensure a data can only be emitted once, a simple modification to LiveData is enough ([SingleLiveData](https://github.com/android/architecture-samples/blob/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/SingleLiveEvent.java)

## Summary

So, when should you use StateFlow and SharedFlow? If you need them! Use the right tool for the right job.

If you need to store or buffer flow elements, if you need to support KMM in your project, or if you need first-class support for stream operation, then please use StateFlow and SharedFlow 🙏. 

If you think LiveData is enough for you, don't migrate to StateFlow just yet 😁

### References

Image taken by Samuel from Unsplash: https://unsplash.com/photos/scUBcasSvbE