How to read data from Firebase Realtime Database using get()?
Firebase Realtime Database is a NoSQL cloud-hosted real-time database from Google.

When it comes to reading data from Firebase Realtime Database, there are two options available. The first one is to read the data using a persistent listener, meaning that we’ll always be in sync with the Firebase servers, or we can read the data only once. The first option is very helpful when we need to listen for changes in real-time. We can achieve this using Query’s addValueEventListener() method. This method adds a listener for changes in the data at a particular path in the database. Each time the data changes, the listener will be invoked with an immutable snapshot of the data. However, there are cases in which we need to read the data from the database only once.
Even from the beginning in 2015, it was added in the Firebase Realtime Database Android SDK a method called addListenerForSingleValueEvent(). This method adds a listener for a single change, meaning that we can read the data at a particular path exactly once. This method remains part of the Firebase Realtime Database Android SDK ever since.
On the other hand, Cloud Firestore, the newer massively scalable NoSQL cloud-hosted real-time database from Google, has another type of mechanism for reading the data once. To read a single document, we can use DocumentReference’s get() method that returns a Task<DocumentSnapshot>, while reading multiple documents from a collection, we can use Firestore Query’s get() method that returns an object of type Task<QuerySnapshot>. Both methods read the data only once.
Luckily, starting from version 19.6.0 of Firebase Realtime Database, we have the option to use a get() call too. Because of the inheritance relationship that exists between these two classes, it doesn’t really matter if we are calling get() on a DatabaseReference object or on a Query object, we’ll always read the data precisely once. This method returns an object of type Task<DataSnapshot>.
As we already know, the Firebase APIs are asynchronous. So I’ll try to explain in this article, three ways in which we can get data from Firebase Realtime Database using this new modern added get() method.
The first solution, which is some kind of an old Java habit, is using a callback, that so-called the “Hollywood Principle” which stands for “Don’t call us, we call you”. The second solution is using an Android Architecture Component called LiveData, and the third one, and the most elegant one, in my opinion, is using Kotlin Coroutines.
Let’s get started.
The database on which we are working has the following structure:

As you can see in the database schema, we have a node of products, meaning that each child within that node is a Product object. Here is the corresponding data class:
data class Product(
var name: String? = null,
var price: Int? = null
)Because the result of a Firebase Realtime Database call, will always return either the products or an Exception, we’ll use a Response data class that looks like this:
data class Response(
var products: List<Product>? = null,
var exception: Exception? = null
)Since the response contains one, or the other object, never both, to keep things simple, I have created in the ProductsActivity class, a print() method, that logs either the name of products or the error message:
private fun print(response: Response) {
response.products?.let { products ->
products.forEach{ product ->
product.name?.let {
Log.i(TAG, it)
}
}
}
response.exception?.let { exception ->
exception.message?.let {
Log.e(TAG, it)
}
}
}Callback solution
Now, when it comes to the first solution, the first thing we need to create is an interface:
interface FirebaseCallback {
fun onResponse(response: Response)
}That contains only one abstract method that takes a single argument of type Response. With respect to the MVVM Architecture Pattern, in the ProductsRepository class, we define the “products” DatabaseReference object inside the constructor and create a method for the database call, that takes as a single argument of type FirebaseCallback:





