Kotlin Flow 收集后无法执行代码

kob*_*owo 8 kotlin kotlin-coroutines

我想打完电话后执行一些代码collectFlow<MyClass>。我对使用 Flows 还是有点陌生​​,所以我不明白为什么函数后面的代码没有被调用。

我如何使用流程:

incidentListener = FirebaseUtils.databaseReference
                      .child(AppConstants.FIREBASE_PATH_AS)
                      .child(id)
                      .listen<MyClass>() //This returns a Flow<MyClass?>?
Run Code Online (Sandbox Code Playgroud)

我如何消耗流量:

private suspend fun myFun() {
   viewmodel.getListener()?.collect { myClass->
       //do something here
   }
   withContext(Dispatchers.Main) { updateUI() } //the code never reaches this part
}
Run Code Online (Sandbox Code Playgroud)

怎么myFun()称呼:

CoroutineScope(Dispatchers.IO).launch {
   myFun()
}
Run Code Online (Sandbox Code Playgroud)

至于我试图让它工作的东西,我已经尝试关闭协程上下文,但它没有用。我假设 Flows 的工作方式与常规协程不同。

更新:

我正在使用此代码块通过 Firebase 进行侦听。我不知道它是否会有所帮助,但也许我实施它的方式导致了问题?

inline fun <reified T> Query.listen(): Flow<T?>? =
callbackFlow {
    val valueListener = object : ValueEventListener {
        override fun onCancelled(databaseError: DatabaseError) {
            close()
        }

        override fun onDataChange(dataSnapshot: DataSnapshot) {
            try {
                val value = dataSnapshot.getValue(T::class.java)
                offer(value)
            } catch (exp: Exception) {
                if (!isClosedForSend) offer(null)
            }
        }
    }
    addValueEventListener(valueListener)
    awaitClose { removeEventListener(valueListener) }
}
Run Code Online (Sandbox Code Playgroud)

kob*_*owo 6

我忘了发布我自己的答案。我以前就发现过这个问题。这是因为我没有归还Coroutine Context

我的代码已经更新了,但以上面的代码为例,它应该写成如下:

private suspend fun myFun() {
   viewmodel.getListener()?.collect { myClass->
       //do something here
       return@collect
   }
   withContext(Dispatchers.Main) { return@withContext updateUI() } 
   //the code should flow downwards as usual
}
Run Code Online (Sandbox Code Playgroud)


Fra*_*esc 5

collect是一个挂起函数,之后的代码collect只会在流程完成后运行。

在单独的协程中启动它:

private suspend fun myFun() {
   coroutineScope {
       launch {
           viewmodel.getListener()?.collect { myClass->
               //do something here
           }
       }
       withContext(Dispatchers.Main) { updateUI() } //the code never reaches this part
    }
}
Run Code Online (Sandbox Code Playgroud)