android Firebase实时数据库与Kotlin协程

2ledvvac  于 2023-03-16  发布在  Android
关注(0)|答案(4)|浏览(155)

我是一个初学者,目前正在Kotlin开发一个Android应用程序,该应用程序从TMDb API获取数据,并使用Firebase实时数据库存储和检索数据。
我使用Kotlin协程从TMDb API获取数据,但我不确定是否应该使用协程存储或检索Firebase实时数据库中的数据。
我希望Firebase自动完成Kotlin协程所做的工作。
下面是我想要执行的Firebase操作之一:(从数据库检索对象)

firebaseDatabase = Firebase.database
        dbReference = firebaseDatabase.getReference("users/$uid")

val dbListener = object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {
                // Get Post object and use the values to update the UI
                val fobject = dataSnapshot.getValue<TvFirebase>()
                Log.v("utk", "tv show name is " + fobject!!.name)
                // ...
            }

            override fun onCancelled(databaseError: DatabaseError) {
                // Getting Post failed, log a message
                Log.w("utk", "onCancelled", databaseError.toException())
                // ...
            }
        }

val tvReference = firebaseDatabase.getReference("users/$uid/tv/236")
            tvReference.addValueEventListener(dbListener)

那么,我是否需要将Kotlin协同程序与Firebase实时数据库一起使用?

iibxawm4

iibxawm41#

我正在使用“实时数据库”和“Firestore”在我的旧项目中添加一些新特性。
由于firestore支持“等待”挂起功能的协程,我搜索了相同的实时数据库。协程是伟大的,如果你不混合挂起和回调函数。
最后自己做。我还没有尝试下面的代码,但它应该工作

注意:自1.2.0以来,一些功能仍标记为ExperimentalCoroutinesApi,因此如果在未来版本中更改,请小心。

sealed class RealtimeDatabaseValueResult {
        class Success(val dataSnapshot: DataSnapshot): RealtimeDatabaseValueResult()
        class Error(val error: DatabaseError): RealtimeDatabaseValueResult()
    }

    /**
     * Perform a addListenerForSingleValueEvent call on a databaseReference in a suspend function way
     * @param onCancellation action to perform if there is a cancellation
     */
    @ExperimentalCoroutinesApi
    suspend fun DatabaseReference.awaitSingleValue(onCancellation: ((cause: Throwable) -> Unit)? = null) = suspendCancellableCoroutine<RealtimeDatabaseValueResult> { continuation ->

        val valueEventListener = object: ValueEventListener{
            override fun onCancelled(error: DatabaseError) {
                continuation.resume(RealtimeDatabaseValueResult.Error(error = error), onCancellation)
            }

            override fun onDataChange(snapshot: DataSnapshot) {
                continuation.resume(RealtimeDatabaseValueResult.Success(snapshot), onCancellation)
            }
        }

        // add listener like you normally do
        addListenerForSingleValueEvent(valueEventListener)

        // in case the job, coroutine, etc. is cancelled, we remove the current event listener
        continuation.invokeOnCancellation { removeEventListener(valueEventListener) }
    }

用法:

fun fetchUser(firebaseDatabase: FirebaseDatabase, userId: String){
        CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate).launch{
            when(val result = firebaseDatabase.getReference("users").child(userId).awaitSingleValue()){
                is RealtimeDatabaseValueResult.Success -> {
                    val dataSnapshot: DataSnapshot = result.dataSnapshot
                    // proceed action with dataSnapshot

                }
                is RealtimeDatabaseValueResult.Error -> {
                    val error: DatabaseError = result.error
                    // proceed action with error
                }
            }
        }
    }
jrcvhitl

jrcvhitl2#

您可以使用callBackFlow API删除所有firebase回调。

override suspend fun getSomething(): Flow<Long> = callbackFlow {
        val valueListener = object: ValueEventListener{

           override fun onCancelled(error: DatabaseError) {
                close()
           }

           override fun onDataChange(snapshot: DataSnapshot) {
              trySend(snapshot.childrenCount)
            }
        }
        currentUserId?.let { userId ->
            firebaseRef?.child(userId)?.addValueEventListener(valueListener)
                    ?: trySend(0)        }

        awaitClose {
            currentUserId?.let { userId ->
                firebaseRef?.child(userId)?.removeEventListener(valueListener)
            }
        }
    }
7kqas0il

7kqas0il3#

没有必要在任何Firebase API中使用协程,但是如果你做得正确的话,这肯定会让你的开发变得更容易。但是,协程与Firebase监听器不兼容,后者会报告随时间变化的值。对于这些监听器,你可能需要使用LiveData或Flow。

hxzsmxv2

hxzsmxv24#

只需对代码做一个小的更改。
从这个...

firebaseDatabase = Firebase.database
        dbReference = firebaseDatabase.getReference("users/$uid")

val dbListener = object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {
                // Get Post object and use the values to update the UI
                val fobject = dataSnapshot.getValue<TvFirebase>()
                Log.v("utk", "tv show name is " + fobject!!.name)
                // ...
            }

            override fun onCancelled(databaseError: DatabaseError) {
                // Getting Post failed, log a message
                Log.w("utk", "onCancelled", databaseError.toException())
                // ...
            }
        }

val tvReference = firebaseDatabase.getReference("users/$uid/tv/236")
            tvReference.addValueEventListener(dbListener)

为了这个...

val firebaseDatabase = FirebaseDatabase.getInstance().getReference("users/$uid")
    
    firebaseDatabse.addChildEventListener(object: ChildEventListener {
    
    override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) {
    Log.d("MainFragment", "Children $snapshot")
    }
    override fun onChildChanged(snapshot: DataSnapshot, previousChildName: String?) {}
    override fun onChildRemoved(snapshot: DataSnapshot) {}
    override fun onChildMoved(snapshot: DataSnapshot, previousChildName: String?) {}
    override fun onCancelled(error: DatabaseError) {}
    })

别忘了检查这是否是正确的人;)

相关问题