简体   繁体   中英

firestore, coroutine and flow

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

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 */)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM