简体   繁体   English

停止和重复协程的最佳方式,kotlin

[英]Best way to stop and repeat coroutine, kotlin

I have an android app that draws time consuming graphs when slider moves.我有一个 android 应用程序,它在 slider 移动时绘制耗时的图表。 If slider moves fast I want to stop current drawing of graph and restart it.如果 slider 移动得很快,我想停止当前的图形绘制并重新启动它。 Once slider stops I finish the last job.一旦 slider 停止,我就完成了最后一项工作。 I am using coroutine for drawing it.我正在使用协程来绘制它。 What is the best way to stop a coroutine and then start it over?停止协同程序然后重新启动它的最佳方法是什么?

There is no builtin restart operation for coroutines, but you can just cancel() already running one and invoke launch() (or any other coroutine builder) again to start it from the beginning.协程没有内置的重启操作,但您可以只cancel()已经运行的协程并再次调用launch() (或任何其他协程构建器)以从头开始启动它。

But... for your specific case I suggest reading about reactive programming and especially about: RxJava or Kotlin flows .但是...对于您的具体情况,我建议阅读有关反应式编程的内容,尤其是有关: RxJavaKotlin 流程的内容。 They were invented specifically to solve these kinds of problems.它们是专门为解决此类问题而发明的。

See this example using flows:使用流程查看此示例:

suspend fun main() {
    // simulate slider position changes
    val sliderFlow = flow {
        emit(1)
        delay(50)
        emit(2)
        delay(50)
        emit(3)
        delay(50)
        emit(4)
        delay(800)
        emit(5)
        delay(1500)
        emit(6)
    }
    sliderFlow.collectLatest { drawGraph(it) }
}

suspend fun drawGraph(input: Int) {
    println("started drawing $input...")
    try {
        delay(1000) // simulate drawing
    } catch (e: CancellationException) {
        println("cancelled drawing $input")
        throw e
    }
    println("ended drawing $input")
}

sliderFlow is a stream of slider positions (created for testing purposes). sliderFlow是一个 stream 的 slider 个位置(为测试目的而创建)。 For each new position drawGraph() is invoked which takes 1000ms to finish.对于每个新的 position,调用drawGraph()需要 1000 毫秒才能完成。 As we are only interested in the latest position, we use collectLatest() which automatically cancels the processing of a value if a new one arrives.由于我们只对最新的 position 感兴趣,因此我们使用collectLatest() ,如果有新值到达,它会自动取消对值的处理。 It produces this output:它产生这个 output:

started drawing 1...
cancelled drawing 1
started drawing 2...
cancelled drawing 2
started drawing 3...
cancelled drawing 3
started drawing 4...
cancelled drawing 4
started drawing 5...
ended drawing 5
started drawing 6...
ended drawing 6

As we can see, only 5 and 6 has completed, the rest was cancelled, because new slider value was emitted before drawGraph() was able to finish.正如我们所见,只有56完成了,rest 被取消了,因为在drawGraph()能够完成之前发出了新的 slider 值。

Additionally, if the slider can move really fast, then we probably don't want to start drawing for each new value, because then we would start drawing only to cancel just milliseconds later.此外,如果 slider 可以移动得非常快,那么我们可能不想为每个新值开始绘制,因为那样我们开始绘制只是为了在几毫秒后取消。 In that case we can use debounce() which will wait for the value to "stabilize" for specified amount of time:在这种情况下,我们可以使用debounce() ,它将等待值在指定的时间内“稳定”:

sliderFlow
    .debounce(100)
    .collectLatest { drawGraph(it) }

Output: Output:

started drawing 4...
cancelled drawing 4
started drawing 5...
ended drawing 5
started drawing 6...
ended drawing 6

As we can see, we didn't even start drawing 1 , 2 and 3 , because they were replaced with new values too quickly.如我们所见,我们甚至没有开始绘制123 ,因为它们被新值替换得太快了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM