【问题标题】:How do you call a suspend function inside a SAM?如何在 SAM 中调用挂起函数?
【发布时间】:2019-10-07 02:12:01
【问题描述】:

我正在尝试创建一个需要从回调中发出值的Flow,但我无法调用emit 函数,因为 SAM 是一个普通函数

这是来自库的带有 SAM 的类,我无法真正按照我需要的方式对其进行修改。

class ValueClass {

    fun registerListener(listener: Listener) {
        ...
    }    

    interface Listener {
        fun onNewValue(): String
    }
}

这是我对创建 Flow 对象的看法

class MyClass(private val valueClass: ValueClass) {
    fun listenToValue = flow<String> {
        valueClass.registerListener { value ->
            emit(value) // Suspension functions can only be called on coroutine body
        }
    }
}

我想如果我可以更改 ValueClass 会很简单,但在这种情况下,我不能。我一直在思考这个问题并试图寻找实现。

至少据我目前所知,一种解决方案是像这样使用GlobalScope

class MyClass(private val valueClass: ValueClass) {
    fun listenToValue = flow<String> {
        valueClass.registerListener { value ->
            GlobalScope.launch {
                emit(value)
            }
        }
    }
}

现在,这可行,但我不想使用 GlobalScope,因为我将使用 viewModelScope 将其与我的应用程序的生命周期联系起来。

有什么办法可以解决这个问题吗?

提前致谢。任何帮助将不胜感激!

【问题讨论】:

标签: android kotlin flow kotlin-coroutines


【解决方案1】:

您可以使用callbackFlow 从回调中创建Flow。它看起来像:

fun listenToValue(): Flow<String> = callbackFlow {
    valueClass.registerListener { value ->
        trySend(value)
        channel.close() // close channel if no more values are expected
    }
    awaitClose { /*unregister listener*/ }
}

或者如果回调中只需要一个值,您可以使用suspendCoroutine 或suspendCancellableCoroutine。在这种情况下,listenToValue() 函数必须是 suspend 并稍后从协程调用(例如 someScope.launch):

suspend fun listenToValue(): String = suspendCoroutine { continuation ->
    valueClass.registerListener { value ->
        continuation.resumeWith(value)
    }
}

【讨论】:

    猜你喜欢
    • 2021-11-24
    • 2020-04-13
    • 2021-12-21
    • 2022-01-18
    • 1970-01-01
    • 2021-04-02
    • 1970-01-01
    • 2022-06-24
    • 1970-01-01
    相关资源
    最近更新 更多