【问题标题】:How do I wait for the first function to finish before executing the second function in Kotlin?在 Kotlin 中执行第二个函数之前,如何等待第一个函数完成?
【发布时间】:2021-08-21 19:24:57
【问题描述】:

所以我有一个简单的代码

try_button.setOnClickListener {
        GlobalScope.launch {
            fun1()
            fun2()
        }
    }

private fun fun1(){
    Timer().schedule(5000){
        println("THIS IS THE FIRST FUNCTION")
    }
}
private fun fun2(){
    println("THIS IS THE SECOND FUNCTION")
}

我想运行第一个函数,第一个函数完成后,继续执行第二个函数。

我尝试了很多代码,但我总是得到结果

THIS IS THE SECOND FUNCTION
THIS IS THE FIRST FUNCTION

我可以等待第一个函数完成后再继续第二个函数吗?

【问题讨论】:

  • 使用 runBlocking。
  • @RishabhKumarSingh 我想向任何可能看到此评论的人指出这是very dangerous advicerunBlocking 不应在生产代码中使用,除非在极其特殊的情况下。 (此外,它实际上根本无法解决这里的问题,因为这两个函数都会立即返回而不会暂停,而这里的问题更多的是逻辑错误......)
  • @Moira 非常感谢。一个疑问,如果我想要一个数据库操作并且没有它的结果就无法继续。那我怎么管理?我不应该使用挂起函数吗?

标签: android kotlin kotlin-coroutines coroutine


【解决方案1】:

如果替换,则使用挂起作为 fun1 是正确的

Timer().schedule(5000) {
    println("THIS IS THE FIRST FUNCTION")
}

delay(5000L)
println("THIS IS THE FIRST FUNCTION")

所以:

private suspend fun fun1() {
    delay(5000L)
    println("THIS IS THE FIRST FUNCTION")
}

private fun fun2() {
    println("THIS IS THE SECOND FUNCTION")
}

Timer().schedule(5000) 不是挂起函数,所以挂起 fun1 不会做任何事情。事实上 Timer().schedule(5000) 使用与 GlobalScope.launch 不同的线程,因此该操作在协程线程池之外执行,这意味着您无法同步两个函数调用,除非手动(例如使用信号量)。

如果您想在结果上同步,使用 async / await 将是一种解决方案(您的问题暗示了其他方式)。如果你想使用异步,只有 fun1 需要 async/await,因为 fun2 只是一个常规函数(无需延迟,无需暂停)。

只是为了好玩,使用信号量的解决方案

val lock = Semaphore(1)

fun main() {
    GlobalScope.launch {
        fun1()
        fun2()
    }
}

private suspend fun fun1() {
    lock.acquire()
    Timer().schedule(5000) {
        println("THIS IS THE FIRST FUNCTION")
        lock.release()
    }
}

private suspend fun fun2() {
    lock.acquire()
    println("THIS IS THE SECOND FUNCTION")
}

信号量可以在挂起(fun2)之前获取一次,并在许可证释放后(通过 fun1)恢复。

【讨论】:

    【解决方案2】:

    根据您的用例,更好的选择将是使用 asyncawait 它基本上是做什么的,您将请求 fun1 它等待结果 1 一旦完成,它将继续进行进一步的过程,这很有趣 2 即使你在 fun1 中设置了一些延迟,它仍然会依次运行 fun1 然后 fun2,这里是代码 sn-p:

    只是从某处获取数据的常规函数​​

    private suspend fun fun1(): String {
        delay(3000L)
        return "Result 1"
    }
    
    
    private fun fun2(): String {
        return "Result 2"
    }
    
    

    顺序调用:

       val result1 = async {
                fun1()
            }
            println(result1.await())
    
    
            val result2 = async {
                fun2()
            }
            println(result2.await())
    

    输出

    Result 1
    Result 2
    

    【讨论】:

    • fun2 不需要使用 async/await,因为 fun2 只是一个常规函数,而不是一个挂起函数
    • @EmanuelMoecklin 的用例是,他想要一些即使有延迟也能按顺序运行的东西,而不仅仅是暂停功能。 async 是什么使请求成功或失败,await 是什么它等待结果以进行进一步处理。 fun2也是如此。 async/await 不仅用于挂起功能,而且有助于使代码顺序化,或者您也可以使其并行化。我会进一步参考这个 kotlinconf:youtube.com/watch?v=w0kfnydnFWI
    • 挂起函数默认是连续的,所以不需要异步/等待。如果您想同时运行多个产生结果的协程,则使用 Async/await。 Async 产生一个类似于 Java Feature 或 JavaScript Promise 的延迟对象。重要的部分是 Async 很热,因此它会立即开始执行。另请参阅kotlinlang.org/docs/…
    • 只是为了让“热”部分更清晰,使用您的代码,fun1 和 fun2 将立即被调用,因此如果您将 print 语句放在两个函数的顶部,它将同时打印两者即使结果是按顺序返回的。这与 OP 想要的完全相反,并发执行与顺序执行。
    【解决方案3】:

    您正在使用 launch 但未使用 suspend 函数。让你的函数挂起函数并使用delay,这是一个设计为等待的suspending 函数。

    try_button.setOnClickListener {
            GlobalScope.launch {
                fun1()
                fun2()
            }
        }
    
    private suspend fun fun1(){
        delay(5000)
        println("THIS IS THE FIRST FUNCTION")
    }
    private suspend fun fun2(){
        println("THIS IS THE SECOND FUNCTION")
    }
    

    请查看the documentation,了解有关协程如何工作的更多信息。

    【讨论】:

    • fun2不用暂停
    【解决方案4】:

    添加暂停关键字。它会暂停你的执行

    try_button.setOnClickListener {
                GlobalScope.launch {
                    fun1()
                    fun2()
                }
            }
    
    suspend fun fun1(){
        delay(1000)
        println("THIS IS THE FIRST FUNCTION")
    }
    fun fun2(){
        println("THIS IS THE SECOND FUNCTION")
    }
    

    【讨论】:

    • 感谢您的帮助,它有效,但如果我的 fun1 尝试从 Firebase 获取结果,它就无效
    猜你喜欢
    • 1970-01-01
    • 2019-02-16
    • 1970-01-01
    • 2020-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-16
    • 1970-01-01
    相关资源
    最近更新 更多