Kotlin 异步回调转为协程

suspendCoroutine() 方法 和 suspendCancellableCoroutine() 方法都可以将异步转为协程。
通过 continuation.resume() 传递结果,continuation.resumeWithException() 传递异常。

public suspend inline fun <T> suspendCoroutine(crossinline block: (Continuation<T>) -> Unit): T {
    contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
    return suspendCoroutineUninterceptedOrReturn { c: Continuation<T> ->
        val safe = SafeContinuation(c.intercepted())
        block(safe)
        safe.getOrThrow()
    }
}
public suspend inline fun <T> suspendCancellableCoroutine(crossinline block: (CancellableContinuation<T>) -> Unit): T =
    suspendCoroutineUninterceptedOrReturn { uCont ->
        val cancellable = CancellableContinuationImpl(uCont.intercepted(), resumeMode = MODE_CANCELLABLE)
        /*
         * For non-atomic cancellation we setup parent-child relationship immediately
         * in case when `block` blocks the current thread (e.g. Rx2 with trampoline scheduler), but
         * properly supports cancellation.
         */
        cancellable.initCancellability()
        block(cancellable)
        cancellable.getResult()
    }

区别,suspendCancellableCoroutine()
可以在 cancelled 时进行响应处理,比如关闭资源;
可以在 resume 时却发现已经 cancelled 时,关闭返回的资源。

suspend fun getResultResourceSuspend(): ResultResource =
    suspendCancellableCoroutine { continuation ->
        val parentResource = ParentResource() // Open parent resource

        continuation.invokeOnCancellation { cause ->
            parentResource.close()  // Ensures parent resource is closed on cancellation
        }

        parentResource.getResultResourceAsync(object : ParentResource.Callback {
            override fun onSuccess(resultResource: ResultResource) {
                continuation.resume(resultResource) { cause ->
                    resultResource.close() // Close sub resource on cancellation
                }
                if (!continuation.isCancelled) parentResource.close()
            }

            override fun onFailure(cause: Throwable) {
                continuation.resumeWithException(cause)
                if (!continuation.isCancelled) parentResource.close()
            }
        })
    }

使用举例:

@RequiresApi(Build.VERSION_CODES.O)
object CallbackToCoroutineTest {
    fun printMsg(msg: String) = println("${LocalDateTime.now()} ${Thread.currentThread()} : $msg")

    fun printErr(msg: String) = println("${LocalDateTime.now()} ${Thread.currentThread()} !!! $msg")

    abstract class Resource : Closeable {
        init {
            printMsg("open ${toString()}")
        }

        override fun close() {
            printMsg("close ${toString()}")
        }

        override fun toString(): String {
            return "${javaClass.simpleName}@${hashCode()}"
        }
    }

    class ParentResource : Resource() {
        interface Callback {
            fun onSuccess(resultResource: ResultResource)

            fun onFailure(cause: Throwable)
        }

        fun getResultResourceAsync(callback: Callback) {
            thread {
                Thread.sleep(1000)
                when {
                    System.currentTimeMillis().toInt() and 1 == 1 -> {
                        callback.onSuccess(ResultResource())
                    }
                    else -> {
                        callback.onFailure(RuntimeException("failure"))
                    }
                }
            }
        }
    }

    class ResultResource : Resource()

    @JvmStatic
    fun main(args: Array<String>) {
        println()

        val parentResource = ParentResource()
        parentResource.getResultResourceAsync(object : ParentResource.Callback {
            override fun onSuccess(resultResource: ResultResource) {
                printMsg("callback onSuccess: $resultResource")
                resultResource.close()
                parentResource.close()
            }

            override fun onFailure(cause: Throwable) {
                printErr("callback onFailure: $cause")
                parentResource.close()
            }
        })

        runBlocking {
            val job: Job = launch {
                try {
                    val resultResource = getResultResourceSuspend()
                    printMsg("coroutine success: $resultResource")
                    resultResource.close()
                } catch (e: Throwable) {
                    printErr("coroutine failed: $e")
                }
            }
            delay(100)
            //job.cancel()
        }

        Thread.sleep(2000)
        println()
    }

    suspend fun getResultResourceSuspend(): ResultResource =
        suspendCancellableCoroutine { continuation ->
            val parentResource = ParentResource() // Open parent resource

            continuation.invokeOnCancellation { cause ->
                parentResource.close()  // Ensures parent resource is closed on cancellation
                printErr("****** invokeOnCancellation $cause")
            }

            parentResource.getResultResourceAsync(object : ParentResource.Callback {
                override fun onSuccess(resultResource: ResultResource) {
                    continuation.resume(resultResource) { cause ->
                        printErr("****** resume onCancellation $cause")
                        resultResource.close() // Close result resource on cancellation
                    }
                    if (!continuation.isCancelled) parentResource.close()
                }

                override fun onFailure(cause: Throwable) {
                    continuation.resumeWithException(cause)
                    if (!continuation.isCancelled) parentResource.close()
                }
            })
        }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值