```suspend fun flowsWithCombine() { val my...
# coroutines
a
Copy code
suspend fun flowsWithCombine() {
        val myFlow = flowOf("some value")
        val lettersFlow = flowOf("A", "D1", "C",  "E", "F", "G", "H").onEach { delay(500) }
        myFlow.map { value->
            val newValue = lettersFlow.first() 
            println("before $newValue")
            if(newValue == "D1") {
                return@map "D1"
            }else {
                delay(1000)
                val newValue = lettersFlow.first() // here i still get A only though i expect newValue as D1
                 println("after $newValue")
                if(newValue == "D1")  return@map "D1" else return@map value
            }
        }.collect {
            println(it) // This should print D1 
        }
    }
s
Each time you call
.first()
on lettersFlow, you're collecting the flow again from the start
1
a
@Sam But i dont want to keep collecting the lettersflows. Once I receive D1 I want to stop there. If I use combine I will keep getting other letters.
s
Use something like
takeWhile
or
transformWhile
to make
lettersFlow
stop once it has emitted
D1
a
@Sam Not sure if you meant this But this is not working
Copy code
suspend fun flowsWithCombine1() {
        var isDone = false
        val myFlow = flowOf("value").onEach { delay(1000) }
        val lettersFlow = flowOf("A", "B", "C", "D1", "E", "F", "G", "H").onEach { delay(100) }
        myFlow.combine(lettersFlow){value , letter ->
            println("one = $value and two = $letter")
            if ("D1" == letter){
                isDone = true
                return@combine letter
            }else {
                return@combine value
            }
        }.takeWhile{
            isDone
        }.collect {
            println(it)
        }
    }
s
More like this:
Copy code
suspend fun flowsWithCombine1() {
    val myFlow = flowOf("value").onEach { delay(1000) }
    val lettersFlow = flowOf("A", "B", "C", "D1", "E", "F", "G", "H")
        .onEach { delay(100) }
        .transformWhile { emit(it); it != "D1" }
    myFlow.combine(lettersFlow) {value , letter ->
        println("one = $value and two = $letter")
    }.collect()
}
a
@Sam Apologies if i my question was not clear .I actually want to listen to myflow first and the value that i receive from myflow will be compared with the letterflow values and if i receive D1 give it to the collect and stop listening if i did not receive D1 from letterflow i still want to wait for like 200 millis and again want to check if letterflow emited D1 if yes then return D1 else return what ever was returned from myflow and stop listening .
s
🤔 I see. So you wait for
myFlow
to emit a value, and then you wait for
letters
to emit
D1
, but with a timeout.
Do you need to collect the two flows in parallel?
I'm assuming you want to start collecting the
lettersFlow
while you're waiting for
myFlow
a
@Sam Basically letterFlow need not be listened until myflow has emitted its value but once myflow has emited a value check if the D1 is emited on the letterflow if it did not , still wait for few millis and check again if we get D1 return that else return whatever is emitted from myflow and stop listening everything,
@Sam no sure but i think if i can change the letterflow into a stateflow then I can solve my problem with the code I posted first in the question. As everytime letterflow will have only one value and letterFlow.first() would return the first latest value in the flow and I can check if it is D1.
n
Is your real lettersFlow "hot" (does it represent events that occur regardless of if there's a listener)? Is it events, or is it state that you want. "the latest letter" could be state, even if the letters come in as events, but you have no idea how old that state is. Also, you can miss events since
StateFlow
only cares about the latest. If you want to wait for the actual event though, don't model it as state.
SharedFlow
works for events. Do you actually want to delay and check again? If "D1" arrives, but then "C" comes before you resume, do you want to just return "some value" or do you want to not miss that "D1"? Do you want to wait for an event, then wait for a delay, and then wait for an event? Or do you want to wait up to 1 sec for a particular event? I suspect you actually want something more like:
Copy code
suspend fun flowsWithCombine() = coroutineScope {
    val myFlow = flowOf("some value")
    val lettersFlow = flowOf("A", "D1", "C",  "E", "F", "G", "H")
        .onEach { delay(400) } //Make D1 arrive BEFORE 1000
        .shareIn(this, SharingStarted.Eagerly) //Guessing you want "hot" Flow
    myFlow.map { value ->
        withTimeoutOrNull(1000) { //Wait at most 1 sec
            lettersFlow.firstOrNull { it == "D1" } //Wait for "D1"
        } ?: value //Fallback if we didn't see the event
    }.collect {
        println(it)
    }
}