0

I wrote a flow that emits integers, and two downstream flows that emit just odd or even numbers. I'm only getting values from the last-created SharedFlow:

b: 1
b: 3
b: 5
b: 7
...

Is there a better way to implement tee'ing a SharedFlow?

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun main() = runBlocking {
    launch { Flows.evens(this).collect { println("a: $it") } }
    launch { Flows.odds(this).collect { println("b: $it") } }
}

object Flows {
    private val flow: Flow<Int> = flow {
        for (i in 0..1000) {
            emit(i)
            runBlocking { delay(100) } // To simulate device polling period.
        }
    }

    private val sharing = SharingStarted.Eagerly

    fun evens(scope: CoroutineScope) = flow.shareIn(scope, sharing).filter { it % 2 == 0 }.shareIn(scope, sharing)

    fun odds(scope: CoroutineScope) = flow.shareIn(scope, sharing).filter { it % 2 == 1 }.shareIn(scope, sharing)
}

Here's that example in the Kotlin playground: https://pl.kotl.in/PtINcEAWD

context: Using a polling input API, I'm reading the status of a game controller and want to multicast updates. This seemed like a job for SharedFlow. I often want to respond only to the updates of a particular button, or to just one joystick, so teeing the flow and adding a filter seemed like a natural way to handle that.

Curtis
  • 536
  • 4
  • 10

1 Answers1

0

I figured out a pattern that seems to work. I suspect it could be more idiomatic.

import kotlinx.coroutines.*
import kotlin.concurrent.thread
import kotlinx.coroutines.flow.*

fun main() = runBlocking {
    launch { Flows.evens().collect { println("even: $it") } }
    launch { Flows.evens().collect { println("even2: $it") } }
    launch { Flows.odds().collect { println("odd: $it") } }
}

object Flows {
    private val mutableSharedFlow = MutableSharedFlow<Int>()
    private val shared = mutableSharedFlow.asSharedFlow()
    init {
        val scope = CoroutineScope(Dispatchers.IO)
        scope.launch {
            for (i in 0..1000) {
                println("writing $i-----------")
                mutableSharedFlow.emit(i)
                delay(100) // To simulate device polling period.
            }
        }
        println("initialized")
    }

    fun evens() = shared.filter { it % 2 == 0 }
    fun odds() = shared.filter { it % 2 == 1 }
}
Curtis
  • 536
  • 4
  • 10