Android Kotlin联合例程-从联合例程返回一个值,而不阻塞主线程
我对合作程序比较陌生,我正在尝试获得启动合作程序将实现的行为:Android Kotlin联合例程-从联合例程返回一个值,而不阻塞主线程,android,kotlin,kotlin-coroutines,Android,Kotlin,Kotlin Coroutines,我对合作程序比较陌生,我正在尝试获得启动合作程序将实现的行为: launch(UI) { val v1 = someDeferredType val v2 = v1.await() val v3 = v2.text } 在上面的示例中,v3将等待v2执行,然后在不阻塞主线程的情况下运行。虽然这很好,但在我的调用活动/片段中引入了延迟类型和协同例程逻辑 我希望我的活动/片段不受具体实现细节的影响,比如: fun getResponseString() :
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 co例程,但这会完全阻止主线程,而不像launch
也许我遗漏了什么,或者在Kotlin中使用Co例程不可能做类似的事情 不能从常规函数(如
getResponseString
)返回异步操作的结果。常规函数不具备在不阻塞调用它们的线程的情况下暂停执行的能力。这就是Kotlin必须引入“挂起函数”概念的原因,因此您可以编写:
suspend fun getResponseString(): String {
val v1 = someDeferredType
val v2 = v1.await()
val v3 = v2.text
return v3
}
将suspend
修饰符添加到所有异步函数(必须等待但不应阻止UI线程的函数)中,然后仅在需要启动一些自包含异步操作的顶层使用launch(UI){…}
另外,协同程序也拼写为“协同程序”。这是一个字,没有破折号。例如,请参见。常规函数和挂起函数之间的区别不仅仅是实现细节:它改变了程序的语义。使用同步代码,您知道它执行的所有操作都是在调用任何其他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()
您不能挂起在主线程上运行的任何调用,您需要使用回调接口。@Pawel-因此本质上,我要么在UI代码中编写launch,要么回退到接口回调机制,对吗?常规函数和挂起函数之间的区别不仅仅是形式上的或实现细节:它改变了程序的语义。使用同步代码,您知道它执行的所有操作都是在调用任何其他UI事件处理程序之前执行的。异步代码失去了原子性,进入了“异步地狱”的世界,事件处理程序彼此并发运行。