是否有可能暂停一个协程超时?

时间:2018-02-25 14:09:03

标签: kotlin kotlin-coroutines

我想要的是这样的功能:

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

这与现有的suspendCoroutine函数基本相同,但是如果回调或块中提供的任何内容在指定的超时内被调用,则corutine会继续,但是会出现TimeoutException或者像这一点。

4 个答案:

答案 0 :(得分:7)

您可以直接合并withTimeoutsuspendCancellableCoroutine以获得所需的效果:

suspend inline fun <T> suspendCoroutineWithTimeout(
    timeout: Long, unit: TimeUnit,
    crossinline block: (Continuation<T>) -> Unit
) = withTimeout(timeout, unit) {
    suspendCancellableCoroutine(block = block)
}

答案 1 :(得分:1)

如果你正在使用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's answer中所述。我建议你在项目中使用这种方法。

答案 2 :(得分:1)

@Roman Elizarov的完美回答。只是在上面加上我的2美分,因为我需要从该通话中返回。返回它将是...

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
}

答案 3 :(得分: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("参数不一样,刷新一波")
            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,满足条件才会返回。对不起,我的英语不是很好。 ——