英文:
Intermediate flow operators: How to not emit if the transformed value is the same?
问题
以下是您提供的代码的翻译部分:
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)
// 启动秒表
launch {
while(true){
elapsedTime.value = System.currentTimeMillis() - startTime
delay(100)
}
}
// 更新UI
launch {
elapsedTime.map{
it/1000
}.collect{
println("$it 秒")
}
}
}
0 秒
0 秒
0 秒
0 秒
0 秒
0 秒
0 秒
0 秒
0 秒
0 秒
1 秒
1 秒
1 秒
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)
// 启动秒表
launch {
while(true){
elapsedTime.value = (System.currentTimeMillis() - startTime)/1000
delay(5)
}
}
// 更新UI
launch {
elapsedTime.collect{
println("$it 秒")
}
}
}
0 秒
1 秒
2 秒
3 秒
您想要从一个根流elapsedTime.value = System.currentTimeMillis() - startTime
中创建多个观察者,并使用.map{it/a}
来实现不同精度级别的观察。这是一个可行的方法,您已经在第一个示例中成功实现了这一点。通过在根流上应用.map
操作,您可以派生出具有不同精度的多个观察者。在第一个示例中,您将毫秒转换为秒以获得更低的精度。
如果您有任何其他问题或需要进一步的帮助,请随时提问。
英文:
I am trying to code a stopwatch using flows.
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
The problem is that intermediate flows do not keep track of whether the value changed like the following code:
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
I want to have a single root flow elapsedTime.value = System.currentTimeMillis() - startTime
from which I can have multiple observers with different levels of accuracy using .map{it/a}
. Is there a clean way to accomplish this?
答案1
得分: 1
是的,使用 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)
// 更新界面
elapsedTime.map { it / 1000L }
.distinctUntilChanged()
.onEach { println("$it 秒") }
.launchIn(this)
launch {
elapsedTime.map { it / 100L }
.distinctUntilChanged()
.collect { println("$it 十分之一秒") }
}
}
英文:
Yes, using distinctUntilChanged()
. And just as an example of different way to create the flow without having to use MutableStateFlow, I used the flow
builder with stateIn
. And an alternate (my preferred) way to collect a flow in its own coroutine using onEach
/launchIn
instead of collect
/launch
for less code indentation and nested brackets.
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") }
}
}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论