【问题标题】:Unable to Execute code after Kotlin Flow collectKotlin Flow 收集后无法执行代码
【发布时间】:2020-09-12 15:22:04
【问题描述】:

Flow<MyClass> 上调用collect 后,我正在尝试执行一些代码。我对使用 Flows 还是有点陌生​​,所以我不明白为什么函数后面的代码没有被调用。

我如何使用 Flow:

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

我如何使用 Flow:

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

myFun() 的调用方式:

CoroutineScope(Dispatchers.IO).launch {
   myFun()
}

就我尝试使其工作而言,我尝试关闭协程上下文,但它没有工作。我假设 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) }
}

【问题讨论】:

    标签: kotlin kotlin-coroutines


    【解决方案1】:

    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
        }
    }
    

    【讨论】:

    • 您好,我刚刚尝试过这种方法,但没有成功。我的流程正在做的是监听 Firebase 更改(我将在我的帖子中添加)我想知道我正在监听的方式是否导致代码无法到达我?
    • 帮助我的关键代码是使用launch{}
    【解决方案2】:

    我忘了发布我自己的答案。我之前已经发现了问题。这是因为我没有返回Coroutine Context

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

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

    【讨论】:

      猜你喜欢
      • 2021-10-28
      • 2022-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-02
      • 2018-11-16
      • 1970-01-01
      相关资源
      最近更新 更多