Haris Bin Saif
Haris Bin Saif

Reputation: 78

How to read a document from Firestore in a Kotlin suspend fun

I have a simple login/signup/dashboard app which i am working on. What i do is, i signup a user using firebase signup, and in that call, i add that user information in my collection and that gets added successfully and shows in collection as well. When i log in, the new user gets verified and in order to show the name of user on dashborad, i want to retrieve the name from collection using the ID of currently authenticated user. Look at the code below:

suspend fun getUserData() : User?{

    firestoreDB.collection("users").document(auth.currentUser!!.uid)
        .get()
        .addOnSuccessListener { documentSnapshot ->
            userInfo = documentSnapshot.toObject(User::class.java)!!
        }
    return userInfo
}

When I debugged this piece of code, i found that the part inside the .addOnSuccessListener is not getting execute at all. So, i get null in return.Can anyone one point out what am I doing wrong here?

The function is called from my viewmodel as:

fun getUserData() = viewModelScope.launch{
    val user= repository.getUserData()
    val username = user?.name
}

My Database looks like this: FireStoreDatabase

Upvotes: 0

Views: 1168

Answers (1)

Doug Stevenson
Doug Stevenson

Reputation: 317467

If you want to create a suspend fun using the result of an asynchronous operation that returns a Play services Task object, don't use addOnSuccessListener. get() is asynchronous and returns immediately with the Task object. You will need a way to convert that Task into something that can work with coroutines to suspect the execution of the function until the Task is complete.

There is a library for this: kotlinx-couroutines-play-services. It will add an extension function await() to the task so you can use it in a suspend fun, an also use try/catch to trap errors. In fact, that page shows you the code pattern you will use:

val snapshot = try {
    FirebaseFirestore.getInstance().document("users/$id").get().await()
} catch (e: FirebaseFirestoreException) {
    return@async
}

In your case, more like this:

return firestoreDB
    .collection("users")
    .document(auth.currentUser!!.uid)
    .get()
    .await()
    .toObject(User::class.java)!!

Be sure to have the caller try/catch for errors.

Upvotes: 2

Related Questions