10

我想要的是这样的功能:

suspendCoroutineWithTimeout(timeout: Long, unit: TimeUnit, crossinline block: (Continuation<T>) -> Unit)

这与现有函数的作用基本相同,suspendCoroutine但如果在指定的超时时间内未调用回调或块中提供的任何内容,则协程将继续,但会出现 TimeoutException 或类似的情况。

4

4 回答 4

34

您可以以简单的方式组合withTimeoutsuspendCancellableCoroutine获得所需的效果:

suspend inline fun <T> suspendCoroutineWithTimeout(
    timeout: Long, unit: TimeUnit,
    crossinline block: (Continuation<T>) -> Unit
) = withTimeout(timeout, unit) {
    suspendCancellableCoroutine(block = block)
}
于 2018-02-25T16:56:17.763 回答
9

@Roman Elizarov 的完美回答.. 只需添加我的 2 美分,因为我需要从那个电话中获得回报.. 所以添加 T?返回它会是......

suspend inline fun <T> suspendCoroutineWithTimeout(timeout: Long, crossinline block: (Continuation<T>) -> Unit ) : T? {
    var finalValue : T? = null
    withTimeoutOrNull(timeout) {
        finalValue = suspendCancellableCoroutine(block = block)
    }
    return finalValue
}
于 2019-10-10T21:23:32.943 回答
2

如果您正在使用suspendCoroutine,这意味着您可以完全控制您对所获得的延续所做的操作。例如,您可以将它传递给基于回调的异步 API,此外,还可以传递给将在异常情况下恢复它的计划任务:

suspend fun mySuspendFun(timeout: Long): String {
    val didResume = AtomicBoolean()
    fun markResumed() = !didResume.getAndSet(true)

    return suspendCoroutine { cont ->
        launch(CommonPool) {
            delay(timeout)
            if (markResumed()) {
                cont.resumeWithException(TimeoutException())
            }
        }
        // call Async API, and in the callback, use
        //    if (markResumed()) {
        //        cont.resume(result)
        //    }
    }
}

但是,Kotlin 的标准库支持您的一流用例,如Roman Elizarov 的回答中所述。我建议你在你的项目中使用这种方法。

于 2018-02-25T14:32:59.773 回答
0
suspend inline fun <T> suspendCoroutineWithTimeout(
    timeout: Long,
    crossinline block: (CancellableContinuation<T>) -> Unit
): T? {
    var finalValue: T? = null
    withTimeoutOrNull(timeout) {
        finalValue = suspendCancellableCoroutine(block = block)
    }
    return finalValue
}

suspend inline fun <T> suspendCoroutineObserverWithTimeout(
    timeout: Long,
    data: LiveData<T>,
    crossinline block: (T) -> Boolean
): T? {
    return suspendCoroutineWithTimeout<T>(timeout) { suspend ->
        var observers : Observer<T>? = null
        val oldData = data.value
         observers = Observer<T> { t ->
             if (oldData == t) {
                 KLog.e("参数一样,直接return")
                 return@Observer
             }
             KLog.e("参数不一样,刷新一波&quot;)
            if (block(t) && !suspend.isCancelled) {
                suspend.resume(t)
                observers?.let { data.removeObserver(it) }
            }
        }

        data.observeForever(observers)
        suspend.invokeOnCancellation {
            KLog.e("删除observiers")
            observers.let { data.removeObserver(it) }
        }
    }
}

前面@Roman Elizarov 和@febaisi 的回答都已经回答的很好了,我在此基础上加了类型判断和livedata,满足条件才会返回。对不起,我的英语不是很好。——</p>

于 2021-07-06T02:20:36.837 回答