我对Co-Routines相对陌生,我正在尝试实现Launch协同例程将完成的行为:
launch(UI) {
val v1 = someDeferredType
val v2 = v1.await()
val v3 = v2.text
}
在上面的示例中,v3将等待v2执行,然后在不阻塞主线程的情况下运行。尽管这很棒,但在我的“呼叫活动/片段”中引入了“延迟类型”和“例程”逻辑。
我想让我的“活动/片段”免于特定的实现细节,例如:
fun getResponseString() : String {
launch(UI) {
val v1 = someDeferredType
val v2 = v1.await()
val v3 = v2.text
}
return v3 //This is the actual String which I need to be returned
}
这样我就可以像我活动中的常规函数一样调用getResponseString()。
到目前为止,我遇到的唯一选择是使用runBlocking协同例程,但这与启动不同,那就是完全阻塞了主线程。
也许我丢失了某些东西,或者无法在Kotlin中使用协例程来做类似的事情?
答案 0 :(得分:1)
您无法从诸如getResponseString
之类的常规函数中返回异步操作的结果。常规函数不具有这种执行挂起功能,而不会阻塞被调用的线程。这就是为什么Kotlin必须引入“暂停功能”的概念,所以您可以这样写:
suspend fun getResponseString(): String {
val v1 = someDeferredType
val v2 = v1.await()
val v3 = v2.text
return v3
}
将suspend
修饰符添加到所有异步函数(必须等待某些东西但不应阻止UI线程的函数),然后仅在最顶层使用launch(UI) { ... }
的想法需要启动一些自包含的异步操作。
P.S。协程也被拼写为“协程”。这是一个字,没有破折号。例如,请参见setState。
答案 1 :(得分:0)
常规函数和挂起函数之间的区别不仅在于实现细节:它还改变了程序的语义。使用同步代码,您知道在执行所有其他UI事件处理程序之前将执行所有操作。您将失去异步代码的原子性,并进入事件处理程序彼此并发运行的“异步地狱”世界。
Kotlin清楚地表明了这一事实,这太棒了:只要您的代码路径未输入协程生成器,您就知道您具有原子性保证。您必须始终明智地选择丢失它的位置,因为一旦这样做,所有其他程序的复杂性就会增加。
写作时
override fun onSomething() {
val v0 = getV0()
launch(UI) {
val v1 = getV1Async()
val v2 = v1.await()
useV2ToUpdateTheGUI(v2)
}
val v4 = getV4()
}
这将是您的处理程序代码的执行顺序:
v0 = getV0()
v4 = getV4()
onSomething
处理程序返回v1 = getV1Async()
v2 = v1.await()
useV2ToUpdateTheGUI(v2)
您的onSomething
处理程序返回上面的3后,将运行不受控制的未知代码量。最臭名昭著的是,您自己的处理程序将运行,并且不允许任何人假设onSomething
中启动的所有操作均已完成。每当您想使用v2
的值时,都必须添加代码来确定尚不可用的情况。
您可以将launch
调用后面的fun
隐藏在onSomething
后面,但是随后您必须在注释/文档中仔细解释该功能只会触发并发任务。自然,您将无法在处理程序主体中使用该任务的结果。
我的经验是,您应该在处理程序中显式地拥有launch(UI)
,或者应该将方法命名为launchFooBar()
。