kotlin 中间流操作符:如果转换后的值相同,如何不发射?

bpsygsoo  于 2023-06-06  发布在  Kotlin
关注(0)|答案(1)|浏览(227)

我正在尝试使用流来编写秒表。

import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking{
    val startTime = System.currentTimeMillis()
    val elapsedTime = MutableStateFlow(0L)
    // start stopwatch
    launch {
        while(true){
            elapsedTime.value = System.currentTimeMillis() - startTime
            delay(100)
        }
    }

    // update ui
    launch {
        elapsedTime.map{
            it/1000
        }.collect{
            println("$it seconds")
        }
    }
}
0 seconds
0 seconds
0 seconds
0 seconds
0 seconds
0 seconds
0 seconds
0 seconds
0 seconds
0 seconds
1 seconds
1 seconds
1 seconds

问题是中间流不会像下面的代码一样跟踪值是否发生了变化:

import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking{
    val startTime = System.currentTimeMillis()
    val elapsedTime = MutableStateFlow(0L)
    // start stopwatch
    launch {
        while(true){
            elapsedTime.value = (System.currentTimeMillis() - startTime)/1000
            delay(5)
        }
    }

    // update ui
    launch {
        elapsedTime.collect{
            println("$it seconds")
        }
    }
}
0 seconds
1 seconds
2 seconds
3 seconds

我希望有一个单一的根流elapsedTime.value = System.currentTimeMillis() - startTime,从中我可以有多个观察者,使用.map{it/a}具有不同的精度水平。有没有一个干净的方法来实现这一点?

cvxl0en2

cvxl0en21#

使用distinctUntilChanged()。作为创建流而不必使用MutableStateFlow的不同方法的示例,我使用了flow构建器和stateIn。另一种(我喜欢的)方法是在自己的协程中使用onEach/launchIn而不是collect/launch来收集流,以减少代码缩进和嵌套括号。

fun main(): Unit = runBlocking {
    val elapsedTime = flow {
        val startTime = System.currentTimeMillis()
        while(true){
            emit(System.currentTimeMillis() - startTime)
            delay(5)
        }
    }.stateIn(this, SharingStarted.Eagerly, 0L)

    // update ui
    elapsedTime.map { it / 1000L }
        .distinctUntilChanged()
        .onEach { println("$it seconds") }
        .launchIn(this)

    launch {
        elapsedTime.map { it / 100 L }
            .distinctUntilChanged()
            .collect { println("$it deciseconds") }
    }
}

相关问题