Async Firebase with Coroutines
I enjoy all things Mobile and Software Engineering. I am currently a Software Engineer and Android Google Developer Expert based in Germany π©πͺ but from Kenya π°πͺ, whose primary focus has been Mobile for the past 6 years.
I share my experiences, the good, the bad, the ugly, and sometimes random tech talks :)
If you've dabbled with Firebase on the Android platform then you must be familiar with the asynchronous callback functions it provides to handle various states such as success, failure and completion of tasks.
Let's have a quick recap with examples.
In an instance where we want to fetch a collection of documents from our firebase database, we would have something similar to this, I'll be using Firestore for this.
getDb.collection(COLLECTION_NAME)
.get()
.addOnSuccessListener{ querySnapshot ->
for (docs in querySnapshot.result!!.documents)
//Do something for each doc
}
.addOnFailureListener{ e ->
displayErrorMessage(e)
}
This works in most cases but what happens in the event we want to manipulate the result before updating the UI or doing some other configuration?
An example in this instance I want to store data in a list first and perform some operations before loading it up on the UI.
fun getAnimals():List<Animals>{
val animals = mutableListOf<Animal>()
getDb.collection(ANIMAL_COLLECTION)
.get()
.addOnSuccessListener{ querySnapshot ->
for (docs in querySnapshot.result!!.documents){
val animal = docs.toObject(Animal::class.java)
animals.add(animal)
}
}
.addOnFailureListener{ e ->
displayErrorMessage(e)
}
return animals //will always be empty
}
Being asynchronous the result will be delivered much later to avoid blocking the UI thread and no animal will have been added to the list hence you end up with an empty list each time.
Where Coroutines Meet Firebase
Quick Recap
"Coroutines are computer program components that generalize subroutines for non-preemptive multitasking, by allowing execution to be suspended and resumed."- Wikipedia
That's a lot to take in but basically coroutines give us the ability to use asynchronous code in a synchronous way.
With coroutines, we can create a suspending function that helps ensure data is loaded up from firebase before proceeding to other tasks in a non-blocking way and get rid of the async callbacks.
How??
First, you will need to add the play services coroutines dependency to your build.gradle app module build script,this will provide functionality on the Task API that allows waiting for task completion.
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$latest_version"
If you are using another build tool other than Gradle check the maven repo and pick what's relevant in your case.
And with that , you can go ahead and start using it. π
Using the above example we can convert it to this;
//Then wherever you need the result within a coroutine scope
launch{
val animals = getAnimals()
updateUI(animals)
}
And there you have it good to go with no callbacks.




