是否可以暂停带有超时的协程?
Is it possible to suspend a coroutine with a timeout?
我想要的是这样的功能:
suspendCoroutineWithTimeout(timeout: Long, unit: TimeUnit, crossinline block: (Continuation<T>) -> Unit)
这与现有的 suspendCoroutine
函数的作用基本相同,但是如果回调或块中提供的任何内容在指定的超时时间内没有被调用,协程将继续但会出现 TimeoutException 或类似的东西那。
如果您正在使用 suspendCoroutine
,这意味着您可以完全控制您对获得的延续所做的事情。例如,您可以将它传递给 callback-based async 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 的标准库支持您的用例 first-class,如 中所述。我建议你在你的项目中使用这种方法。
您可以直接组合 withTimeout
和 suspendCancellableCoroutine
以获得所需的效果:
suspend inline fun <T> suspendCoroutineWithTimeout(
timeout: Long, unit: TimeUnit,
crossinline block: (Continuation<T>) -> Unit
) = withTimeout(timeout, unit) {
suspendCancellableCoroutine(block = block)
}
来自@Roman Elizarov 的完美回答.. 只需在上面加上我的 2 美分,因为我需要那个电话的 return.. 所以添加 T? return 会是...
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
}
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,只有满足条件才会return。对不起,我的英语不是很好。 –
我想要的是这样的功能:
suspendCoroutineWithTimeout(timeout: Long, unit: TimeUnit, crossinline block: (Continuation<T>) -> Unit)
这与现有的 suspendCoroutine
函数的作用基本相同,但是如果回调或块中提供的任何内容在指定的超时时间内没有被调用,协程将继续但会出现 TimeoutException 或类似的东西那。
如果您正在使用 suspendCoroutine
,这意味着您可以完全控制您对获得的延续所做的事情。例如,您可以将它传递给 callback-based async 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 的标准库支持您的用例 first-class,如
您可以直接组合 withTimeout
和 suspendCancellableCoroutine
以获得所需的效果:
suspend inline fun <T> suspendCoroutineWithTimeout(
timeout: Long, unit: TimeUnit,
crossinline block: (Continuation<T>) -> Unit
) = withTimeout(timeout, unit) {
suspendCancellableCoroutine(block = block)
}
来自@Roman Elizarov 的完美回答.. 只需在上面加上我的 2 美分,因为我需要那个电话的 return.. 所以添加 T? return 会是...
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
}
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,只有满足条件才会return。对不起,我的英语不是很好。 –