
LiveData with Coroutines and Flow — Part III: LiveData and coroutines patterns
This article is part III of a summary of the talk I gave with Yigit Boyar at the Android Dev Summit 2019.
Summary
This article discusses LiveData with Coroutines and Flow, focusing on patterns for using LiveData and Flow in ViewModels and repositories.
Abstract
The article is the third part of a series summarizing a talk given at the Android Dev Summit 2019. It explores patterns for using LiveData and Flow in ViewModels and repositories. The article compares the usage of LiveData and Flow in various scenarios, such as emitting N values as LiveData or Flow, emitting 1 initial value + N values from a data source, and suspend transformations. It also covers patterns for repositories and data sources, including one-shot operations and exposing Flow in the data source. The article concludes by mentioning that coroutines and Flow are here to stay, but they don't replace LiveData everywhere.
Bullet points

This article is part III of a summary of the talk I gave with Yigit Boyar at the Android Dev Summit 2019.
Part II: Launching coroutines with Architecture Components
Part III: LiveData and Coroutines patterns (this post)
Let’s look at some patterns that can be used in ViewModels, comparing LiveData and Flow usages:
If we don’t do any transformations, we can simply assign one to the other.
We could use a combination of the liveData coroutine builder and collect on the Flow (which is a terminal operator that receives each emitted value):
But since it’s a lot of boilerplate, we added the Flow.asLiveData() extension function, which does the same thing in one line:
If the data source exposes a LiveData, we can use emitSource to pipe updates after emitting an initial value with emit:
Again, we could do this naively:
But if we leverage Flow’s own API, things look much neater:
onStart sets the initial value and doing this we just need to convert to LiveData once.
Let’s say you want to transform something coming from a data source but it might be CPU-heavy so it’s in a suspend function.
You can use switchMap on the data source’s LiveData and then create the coroutine with the liveData builder. Now you can just call emit on each result received.
This is where Flow really shines compared to LiveData. Again we can use Flow’s API to do things more elegantly. In this case we use Flow.map to apply the transformation on every update. This time, because we’re already in a coroutine context, we can call it directly:
Not much to say about repositories, as if you’re consuming a Flow and exposing a Flow, you just use the Flow API to transform and combine data:
Again, let’s make the distinction between a one-shot operation and a Flow.
If you’re using a library that supports suspend functions, like Room or Retrofit, you can simply use them from your suspend functions!
However, some tools and libraries do not support coroutines yet and are callback-based.
In that case you can use suspendCoroutine or suspendCancellableCoroutine.
(I don’t know why you would want to use the non-cancellable version though, let me know in the comments!)
When you call it, you get a continuation. In this example we are using an API that let us set a complete listener and a failure listener so in their callbacks we call continuation.resume or continuation.resumeWithException when we receive data or an error.
It’s important to note that if this coroutine is cancelled, resume will be ignored so if your request takes a long time the coroutine will be active until one of the callbacks is executed.
Flow builder
If you need to create a fake implementation of a data source or you just need something simple you can use the flow constructor and do something like this:
This code emits a weather condition every two seconds.
Callback-based APIs
If you want to convert a callback-based API to flows, you can use callbackFlow.
It looks daunting, but if you split it apart you’ll find that it makes a lot of sense.
In conclusion, coroutines and Flow are here to stay! But they don’t replace LiveData everywhere. Even with the very promising StateFlow (currently experimental) we still have the users of the Java Programming Language and Data Binding to support, so it won’ t be deprecated for a while :)
Some links if you want to read more:
My other blog posts about LiveData
Mohamed ElsdodyHandling network requests efficiently requires robust error handling and retry mechanisms, especially in mobile applications where network…
Kotlin Flow is an exciting addition to the Kotlin coroutines library, providing a powerful way to handle asynchronous data streams in…
amod kantheKotlin flow provides an efficient way to handle asynchronous data in the form of streams. A Flow basically emits data asynchronously in the…
Rushabh PrajapatiIn Android development, managing state and handling data changes efficiently is crucial for building responsive and robust applications…