简体   繁体   English

Kotlin Flow 收集后无法执行代码

[英]Unable to Execute code after Kotlin Flow collect

I'm trying to execute some code after calling collect on a Flow<MyClass> .我正在尝试在Flow<MyClass>上调用collect后执行一些代码。 I'm still kind of new to using Flows so I don't understand why the code after the function doesn't get called.我对使用 Flows 还是有点陌生​​,所以我不明白为什么函数后面的代码没有被调用。

How I use the Flow:我如何使用流程:

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

How I consume the Flow:我如何消耗流量:

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

How myFun() is called:如何myFun()

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

As far as what I've tried to make it work I've tried closing the coroutine context and it didn't work.至于我试图让它工作的东西,我已经尝试关闭协程上下文,但它没有用。 I'm assuming Flows work differently than regular coroutines.我假设 Flows 的工作方式与常规协程不同。

Update:更新:

I'm listening through Firebase using this block of code.我正在使用此代码块通过 Firebase 进行侦听。 I don't know if it'll help but maybe the way I implemented it is causing the issue?我不知道它是否会有所帮助,但也许我实施它的方式导致了问题?

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

collect is a suspending function, the code after collect will only run once the flow completes. collect是一个挂起函数, collect之后的代码只会在流程完成后运行。

Launch it in a separate coroutine:在单独的协程中启动它:

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

I forgot to post my own answer to this.我忘了发布我自己的答案。 I've found the problem before.我以前发现过这个问题。 It's because I wasn't returning the Coroutine Context .这是因为我没有返回Coroutine Context

My code has been updated since but with the code above as an example it should be written as follows:我的代码已经更新了,但以上面的代码为例,它应该写成如下:

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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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