【问题标题】:Why can't I call kotlin suspend function under lambda function为什么我不能在 lambda 函数下调用 kotlin 挂起函数
【发布时间】:2025-12-21 08:00:06
【问题描述】:

让我从示例代码 sn-ps 开始

suspend fun executeLive(result: MutableLiveData<Person>) {

    val response = ... //suspend api request

    mediatorLiveData.removeSource(response)

    mediatorLiveData.addSource(response) {
        result.value = sortData(it) // sortData is also suspend function which sortData at Dispatcher.Default
    }

}

在这个例子中,sortData 不能在lambda function 下调用(在这种情况下是addSource)。而且我已经将executeLive 声明为suspend,这就是为什么suspend api 请求可以从第一的。但是sortData函数显示编译时错误

挂起函数只能从协程体中调用

那么我该如何改变我的代码结构来解决这个问题呢?

更新:有没有关于这方面的文章?

【问题讨论】:

  • 你可以launch 一个协程来设置结果的值。但是您应该可以访问适当的CoroutineScope 以避免泄漏。
  • 你可以试试runBlocking { ... }

标签: android kotlin android-livedata kotlin-coroutines


【解决方案1】:

lambda 通常是一个回调函数。回调函数之所以被称为是因为我们将一段代码包装在一个函数中,然后将其传递给其他人(或其他地方)执行。这是一种基本的控制反转,其中代码不是由您执行,而是由其他人执行(例如框架)。

例如,当您在按钮上设置 onClickListener 时,我们不知道它何时会被调用,我们为框架传递一个 lambda,该框架负责处理用户交互以调用指定的操作。

在您的情况下,挂起函数同样不会调用sortdata,而是将其传递给mediatorLiveData 对象以在其自己的上下文中调用它。您传递的 lambda 不必从协程主体中调用,因此这是不允许的。

【讨论】:

  • 我只想补充一点,如果 addSource 是一个内联函数(并且它的参数不是 crossinline),它会起作用,从而保证它在同一范围内调用 lambda。
【解决方案2】:

您可以通过将mediatorLiveData.addSource 调用转换为使用suspendCoroutine 本身的挂起调用来解决此问题:

suspend fun executeLive(result: MutableLiveData<Person>) {

    val response = ... //suspend api request

    mediatorLiveData.removeSource(response)

    val data = suspendCoroutine<TypeOfData> { cont ->
        mediatorLiveData.addSource(response) { cont.resume(it) }
    }

    result.value = sortData(data)
}

无论response 发出的数据类型是什么,我都使用TypeOfData 作为占位符。请注意,这仅在您打算进行单次发射时才有效。

如果需要跟踪多个值,可以尝试callbackFlow

suspend fun executeLive(result: MutableLiveData<Person>) {

    val response = ... //suspend api request

    mediatorLiveData.removeSource(response)

    callbackFlow<TypeOfData> {
        mediatorLiveData.addSource(response) { offer(it) }

        awaitClose { mediatorLiveData.removeSource(response) }
    }
        .collect { result.value = sortData(it) }
}

【讨论】: