No more LiveData in Your Repository: There are better options

Three years ago at a Google I/O that every Android developer remembers, Google announced Android Architecture Components and we were all excited about it.
ACC has definitely changed the way we build Android Applications. ViewModel and LiveData have both taken an important place in our day-to-day app design.
LiveData is the main topic of this post. Don’t get me wrong LiveData is a very powerful and useful component for Android development. It’s an observable Lifecycle-Aware data holder. These few words really mean a lot for us, Android developers.
The all famous Guide to App Architecture shows us how we could use Android Architecture Components together to build an app Architecture. This was actually the first time Google officially wrote a full App architecture recommendation in the official documentation (as far as I know).
So as good developers that we are, we followed this guide “by the book”.
The guide in itself is pretty good and well designed. And it covers everything we need for a typical basic application. But there is one thing that is really interesting about it: The Repository.
In the guide, the Repository looks like this:

Well, let’s get straight to it, shall we?
The first thing we notice is the return Type. The repository function returns a LiveData<User>. This “LiveData In Repository” pattern was widely adopted by developers.
Just like Thanos, with a snap of our fingers, we wiped out all of our RxJava and Callbacks implementation and replaced them with this simple implementation based on LiveData. Since LiveData is observable, this implementation makes real sense (At least that was we thought).

But while this could be just fine, I believe it was never a good idea. For mainly two reasons
1. LiveData Should be kept in the presentation layer
The official documentation definition of LiveData points to the place where LiveData is really useful. These are Activities and Fragments. Because of the Lifecycle-awareness of these components using a LiveData to observe the ViewModel state is simply the right thing to do.
But since we removed all of our RxJava and Callbacks code, how can we handle the asynchronous work performed by the Repository and Data source?
There are mainly two types of requests that could be sent to a Repository.
- One-shot Requests
- Multiple-Value Requests or to put it with simple words, Stream of data
One-shot Requests
In the case of a One-shot Request, a good solution would be to simply take advantage of Kotlin's suspend functions and Coroutines. We will make our Repository return a simple User but the getUser() function will become a suspend function.

In the ViewModel, we will simply use a LiveData builder to create a coroutine that will run the Repo asynchronously, consume the response, and emit a LiveData value.
class UserViewModel(private val userRepo: UserRepository): ViewModel() {
...
val user = liveData {
emit(userRepo.getUser(10))
}
...
}
Boom!
Multiple Values Requests
In the case of Multiple value requests, We could be tempted to actually use LiveData this time. Because we need to keep notifying the presentation layer of all the incoming values. But this is where things get interesting. Kotlin Flow makes its entrance in the building.
Kotlin Flow gives us a way to handle asynchronous data streams. Unlike its cousin Channel, a Flow is referred to as a cold Stream while Channels are hot Streams. All those fancy words to simply say that the values emitted by a Flow are held (actually they’re not even computed) until someone decides to collect them. This is similar to RxJava Observable/Subscriber.
So here, we will make the repository return a Flow of User (Flow<User>) and we will manage to collect the Flow values in the ViewModel and turn them into LiveData value changes.

val user = userRepo
.getUserLikes()
.onStart {
// Emit first value
}
.asLiveData()
As Google’s Jose Alcérreca said in his talk at the Android Dev Summit 19: “LiveData was never designed as a fully-fledged reactive Stream builder so it’s a little bit akward to use”.
2. You shouldn’t bring Android stuff in your Domain
The second important reason to not use LiveData in Repositories for me is the negative impact on the Domain layer modeling.
If you decide to have a Domain layer (And you really should) in your architecture whether you follow Clean Architecture, Domain Driven Design principles, whatever else… or not, there is a very simple rule to respect. The domain should be Platform/Infrastructure agnostic. Oh yeah, here this pretty little word “agnostic”, simply means the Domain knows nothing about the platform implementation details. In even simpler words the Domain shouldn’t know anything about Android stuff.
This is so important that many developers decide to make the Domain a pure Kotlin module with no significant dependencies and definitely no Android dependency at all.
Now since the Domain’s UseCase is placed between the ViewModel and the Repository, by making your Repository return a LiveData, you’re forcing your Domain to support LiveData too. Because In Clean Architecture, for instance, the Domain defines Abstractions for Repositories. That means you’re gonna need to have an androidx.lifecycle:lifecycle-livedata dependency in your Domain Gradle file.
As far as I’m concerned, this is bad.
Let’s wrap it up
In this post, we didn’t focus on details like ViewModelScope, LiveData Builders, Coroutines Structured Concurrency, Flows, and stuff. There are already a lot of excellent articles on these topics. Just Google those terms.
However, We simply wanted to point out the needless choice and the price of using LiveData in Repositories design.
Perhaps you have a better approach or opinion, perhaps you have ways to bypass this? Let me know in the comments and let’s talk about it.
Thank you for reading.
Resources
https://developer.android.com/topic/libraries/architecture/coroutines