usbpc102
usbpc102

Reputation: 1257

Is it possible to suspend a coroutine with a timeout?

What I want is a function like this:

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

That does basically the same thing as the existing suspendCoroutine function but if the callback or whatever was provided in the block dosen't get called within the specified timeout the corutine continues but with a TimeoutException or something like that.

Upvotes: 23

Views: 11116

Answers (3)

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) }
        }
    }
}

The previous @Roman Elizarov and @febaisi answers have been answered very well, I added a type judgment and livedata on this basis, and I will return only when the conditions are met. Sorry, my English is not very good. –

Upvotes: 0

febaisi
febaisi

Reputation: 684

Perfect answer from @Roman Elizarov.. Just adding my 2 cents on it because I needed a return from that call.. So adding T? return it would be ...

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
}

Upvotes: 16

Roman  Elizarov
Roman Elizarov

Reputation: 28648

You can combine withTimeout and suspendCancellableCoroutine in a straightforward way for the desired effect:

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

Upvotes: 68

Related Questions