Differences between LiveData, Flow, SharedFlow, and StateFlow.

Rohail Ahmad
4 min readJan 4, 2023
Photo by Raphael Andres on Unsplash

LiveData & Flow

LiveData is a data holder class that can be observed within a given lifecycle. This means that an observer can be registered to observe LiveData objects and will be notified of any changes to the LiveData object’s value. LiveData is designed to be used with data that is meant to be observed within the UI, and it automatically manages the lifecycle of its observers to ensure that they are only notified when the LiveData is in an active state.

Flow is a new reactive stream that was introduced in Kotlin Coroutines. It is similar to LiveData in that it allows you to observe a stream of data, but it has some key differences:

  • Flow is reactive and can be transformed and processed using operators like map, filter, and reduce.
  • Flow is cold, which means it only starts emitting values when there is at least one active subscriber.
  • Flow is cancellable, which means it can be stopped or canceled by the subscriber.

In summary, LiveData is a data holder that is designed to be observed within the UI, while Flow is a reactive stream that can be transformed and processed using operators and is cancellable. LiveData is suitable for simple cases where you want to observe data within the UI, while Flow is more suitable for more complex cases where you need to process and transform data streams.

Here is an example of how to use LiveData in Kotlin:

class NameViewModel : ViewModel() {

// Create a LiveData with a String
val currentName: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}

// Rest of the ViewModel...
}


class NameActivity : AppCompatActivity() {

// Use the 'by viewModels()' Kotlin property delegate
// from the activity-ktx artifact
private val model: NameViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// Other code to setup the activity...

// Create the observer which updates the UI.
val nameObserver = Observer<String> { newName ->
// Update the UI, in this case, a TextView.
nameTextView.text = newName
}

// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
model.currentName.observe(this, nameObserver)

// Set value
button.setOnClickListener {
val anotherName = "John Doe"
model.currentName.setValue(anotherName)
}
}
}

Here is an example of how to use Flow in Kotlin:

class NewsRemoteDataSource(
private val newsApi: NewsApi,
private val refreshIntervalMs: Long = 5000
) {
val latestNews: Flow<List<ArticleHeadline>> = flow {
while(true) {
val latestNews = newsApi.fetchLatestNews()
emit(latestNews) // Emits the result of the request to the flow
delay(refreshIntervalMs) // Suspends the coroutine for some time
}
}
}

// Interface that provides a way to make network requests with suspend functions
interface NewsApi {
suspend fun fetchLatestNews(): List<ArticleHeadline>
}


class LatestNewsViewModel(
private val newsRepository: NewsRepository
) : ViewModel() {

init {
viewModelScope.launch {
newsRepository.favoriteLatestNews
// Intermediate catch operator. If an exception is thrown,
// catch and update the UI
.catch { exception -> notifyError(exception) }
.collect { favoriteNews ->
// Update View with the latest favorite news
}
}
}
}

There are three entities involved in streams of data:

  • A producer produces data that is added to the stream. Thanks to coroutines, flows can also produce data asynchronously.
  • (Optional) Intermediaries can modify each value emitted into the stream or the stream itself.
  • A consumer consumes the values from the stream.

SharedFlow & StateFlow

SharedFlow and StateFlow are both types of reactive streams that were introduced in Kotlin Coroutines. They are both similar to LiveData in that they allow you to observe a stream of data, but they have some key differences:

  • SharedFlow and StateFlow both are hot flows because their active instance exists independently of the presence of collectors. Its current value can be retrieved via the value property.
  • The main difference between them is that StateFlow is a state-holder observable flow that emits the current and new state updates to its collectors. Which means it holds a default value.
  • The other difference is that you can read the current state value from StateFlow.

Here is an example of how to use SharedFlow in Kotlin:

import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow

fun main() {
val sharedFlow = (1..5).asSharedFlow()
sharedFlow.collect { value ->
println("Subscriber 1: $value")
}
sharedFlow.collect { value ->
println("Subscriber 2: $value")
}
}

In this example, we create a SharedFlow by converting a range of numbers into a flow using the asSharedFlow function. We then subscribe to the flow twice, and each subscriber receives a separate stream of values. The output of this code would be:

Subscriber 1: 1
Subscriber 1: 2
Subscriber 1: 3
Subscriber 1: 4
Subscriber 1: 5
Subscriber 2: 1
Subscriber 2: 2
Subscriber 2: 3
Subscriber 2: 4
Subscriber 2: 5

Here is an example of how to use StateFlow in Kotlin:

import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

fun main() {
val stateFlow = MutableStateFlow(0)
stateFlow.value = 1
stateFlow.value = 2
stateFlow.collect { value ->
println(value)
}
}

In this example, we create a StateFlow by wrapping a mutable state variable in the MutableStateFlow class. We then set the value of the state variable to 1 and 2, and the StateFlow emits these values to its subscriber. The output of this code would be:

1
2

In summary, SharedFlow is a cold flow that allows multiple subscribers and is suitable for publish-subscribe scenarios, while StateFlow is a hot flow that allows only one subscriber and is suitable for broadcast scenarios.

--

--

Rohail Ahmad

Android Engineer with @kivrasweden formerly @Eliq & @Inov8