How to use Kotlin Flows with Firestore

Gastón Saillén
Firebase Tips & Tricks
5 min readMar 5, 2020

A little while ago I was talking about how to do asynchronous calls with Firebase and Coroutines, you can check how to do one time operations to request data using Firestore here

I would recommend taking a look at that previous post to get in the context of what we are going to do, we are going to use one of the coolest features from Firebase, that is Realtime Data flow to our user screen.

If you were using Firebase before, you have worked with its realtime functionality through callbacks

For example, from the documentation we can listen to a reference and update our UI whenever this reference generates/updates/delete a new value, so we deliver that value to the user at the time the user is seeing the screen.

From this code you can see that we are listening to a reference, after a value has changed into Firebase we trigger onDataChange(…) and then handle that value.

We can also attach ListenerForSingleValueEvent to that reference, which will just get the data once and detach the listener to that reference.

In the previous post I mentioned we were doing this kind of operations, these operations are called one time operations because we go and fetch the data and detach any listener to that data, we can see this flow of data this way

As you can see here, we have a repository that uses a suspend function to retrieve the data inside our data source, that data source is Firebase in which we gonna fetch our database for the data to deliver to the view.

How this flow works

  • User needs to fetch some data at our database, let's say that in the View we call a method inside our ViewModel that is called fetchNews()
  • This method fetchNews() will trigger a suspend function that will await until the data from the server completes
  • Our ViewModel will communicate with our repository and this last one with our data source to bring our data
  • After the data has been fetched and propagated from the data source to our ViewModel, we set that data to our MutableLiveData and at that time our observer in the UI fires up with the data fetched.

So, now, how we adapt the code from the previous post from doing one time operations to keep listening for changes in our database?

Simply, we’ll be using Asynchronous flow, if you want to understand how flow works I recommend these two awesome videos

Whit these two videos you are going to understand how flow works and why we are going to use it to deliver data to our view.

Basically flow is a channel in which data comes and leaves, you can see it as a buffer of shared data where on producer puts data in and one consumer collects data from it, at the moment the producer is not putting more elements, there are no more elements that the collector can collect, and then, our collector will be waiting for new values to come in from the producer.

You can see how flow works with this image

As you can see now, we have another “observer ” in our repository, I call it an observer because is listening for new values from our data source, so, if our datasource is Firebase we are always keeping an eye on new values changes, whenever a new value has been changed we put it inside the buffer and we collect it from our viewModel.

That's all how flow works basically.

Now, let's see this in code

How to use Flow with Firestore

First of all, this post is for Android development and this example will apply to it, so to get started, just make sure you have the coroutines dependency at your Gradle, that is

implementation ‘org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3’

Now let's do a request to Firestore to check for a versionCode number and update our UI whenever this versionCode number changes at our database.

You can see this feature as a realtime update system to let users know that a new version has arrived and they need to download it to keep using the app.

From our UI we will be using a method from our ViewModel to fetch this integer

UI

Now, in our ViewModel, we are gonna fire a coroutine to wait for the data to come from our repository

ViewModel

Now, have you noticed something here? We are using .collect on getVersionCode() method, that .collect tells us that getVersionCode() is returning a Flow of data that we are collecting inside our ViewModel

And then we use emit() to emit that collected data to our liveData, here you can see that fetchVersionCode will return a livedata, this liveData(Dispatchers.IO) is a liveData scope to return livedata more easily, we use emit(value) instead of mutableLiveData.value = value and it simplifies our programming code.

You can read more of this here

Now, lets see how getVersionCode() works

Repo

As you can see in the comments of the code, we opened a new channel with callbackFlow from where we are going to offer data to it, this offered data is after consumed in our ViewModel with .collect, we use .addSnapshotListener because is this listener that keeps listening to our data in Firestore and will fire every time a new value changes, after that value changes we offer it to the channel and then consume it in our ViewModel

Doing this we successfully delivered our version code to our UI and we are also listening for new versions to change if the user is in the current Activity that is listening for these values with flow.

You can check and clone the full code in my repo

You can also check this awesome post by Roman Elizarov

--

--