1

firebase method is working on worker thread automatically. but I have used coroutine and callbackflow to implement firebase listener code synchronously or get return from the listener. below is my code that I explained

coroutine await with firebase for one shot

override suspend fun checkNickName(nickName: String): Results<Int> {


    lateinit var result : Results<Int>

    fireStore.collection("database")
        .document("user")
        .get()
        .addOnCompleteListener { document ->


            if (document.isSuccessful) {

                val list = document.result.data?.get("nickNameList") as List<String>

                if (list.contains(nickName))
                    result = Results.Exist(1)
                else
                    result = Results.No(0)

                //document.getResult().get("nickNameList")
            }
            else {

            }
        }.await()

    return result
}

callbackflow with firebase listener

override fun getOwnUser(): Flow<UserEntity> = callbackFlow{

    val document = fireStore.collection("database/user/userList/")
        .document("test!!!!!")

    val subscription = document.addSnapshotListener { snapshot,_ ->

        if (snapshot!!.exists()) {

            val ownUser = snapshot.toObject<UserEntity>()

            if (ownUser != null) {
                trySend(ownUser)
            }
        }
    }

    awaitClose { subscription.remove() }

}

so I really wonder these way is good or bad practice and its reason

1 Answer 1

2

Do not combine addOnCompleteListener with coroutines await(). There is no guarantee that the listener gets called before or after await(), so it is possible the code in the listener won't be called until after the whole suspend function returns. Also, one of the major reasons to use coroutines in the first place is to avoid using callbacks. So your first function should look like:

override suspend fun checkNickName(nickName: String): Results<Int> {
    try {
        val userList = fireStore.collection("database")
            .document("user")
            .get()
            .await()
            .get("nickNameList") as List<String>

        return if (userList.contains(nickName)) Results.Exist(1) else Results.No(0)
    } catch (e: Exception) {
        // return a failure result here
    }
}

Your use of callbackFlow looks fine, except you should add a buffer() call to the flow you're returning so you can specify how to handle backpressure. However, it's possible you will want to handle that downstream instead.

override fun getOwnUser(): Flow<UserEntity> = callbackFlow {
    //...
}.buffer(/* Customize backpressure behavior here */)
Sign up to request clarification or add additional context in comments.

2 Comments

it also use implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.3.1"??
I think so. There may be a few different ways to pull in the ktx extensions for Firestore. Often with Google libraries, you can just add -ktx to the artifact name to find the version with the the extensions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.