从协程获取状态更新

时间:2019-02-07 19:30:56

标签: kotlin callback kotlinx.coroutines

考虑一个异步API,该API报告其操作进度:

suspend fun operationWithIO(input: String, progressUpdate: (String) -> Unit): String {
    withContext(Dispatchers.IO) {
        // ...
    }
}

是否可以实现对progressUpdate的调用,以便在调用者的调度程序上处理回调?还是有更好的方法将状态更新回传给呼叫者?

2 个答案:

答案 0 :(得分:2)

您应该在频道上发送进度更新。这样一来,呼叫者就可以使用所需的任何调度程序来监听频道。

suspend fun operationWithIO(input: String, progressChannel: Channel<String>): String {
    withContext(Dispatchers.IO) {
        // ...

        progressChannel.send("Done!")
        progressChannel.close()
    }
}

呼叫者可以通过执行以下操作来使用它:

val progressChannel = Channel<String>()

someScope.launch {
    operationWithIO(input, progressChannel)
}

// Remember the call to progressChannel.close(), so that this iteration stops.
for (progressUpdate in progressChannel) {
    println(progressUpdate)
}

答案 1 :(得分:0)

如何包装回调函数并调用包装的函数:

/** Return a new callback that invokes this callback on the current context. */
suspend fun <T> ((T) -> Unit).onCurrentContext(): (T) -> Unit =
    coroutineContext.let { context ->
        { value: T ->
            runBlocking {
                launch(context) {
                    this@onCurrentContext.invoke(value)
                }
            }
        }
    }

/** Perform a background operation, delivering status updates on the caller's context. */
suspend fun operationWithIO(statusUpdate: (String) -> Unit): String {
    val cb = statusUpdate.onCurrentContext()
    return withContext(Dispatchers.IO) {
        cb("Phase 1")
        delay(150)
        cb("Phase 2")
        delay(150)
        "Result"
    }
}

// In use
runBlocking {
    val result = operationWithIO {
        println("received callback status $it")
    }
    println("result is $result")
}