Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android Kotlin联合例程-从联合例程返回一个值,而不阻塞主线程_Android_Kotlin_Kotlin Coroutines - Fatal编程技术网

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事件处理程序之前执行的。异步代码失去了原子性,进入了“异步地狱”的世界,事件处理程序彼此并发运行。