Shashank
09/13/2020, 5:57 PMStateFlow
by asserting the list of values received by it.
data class State(val isLoading: Boolean, val name: String?)
fun main() {
val mutableStateFlow = MutableStateFlow(State(false, null))
val stateFlow = mutableStateFlow as StateFlow<State>
val scope1 = CoroutineScope(Job())
val scope2 = CoroutineScope(Job())
scope1.launch {
delay(1000)
mutableStateFlow.value = State(true, null)
mutableStateFlow.value = State(false, "name")
}
scope2.launch {
stateFlow.collect {
println("value = $it")
}
}
Thread.sleep(2000)
}
Here is my code. Instead of getting State(true, null)
as the second value, I only receive the initial value and the last value (State(false, name)
)araqnid
09/13/2020, 6:00 PMdelay(10)
between the two writes to mutableStateFlow.value
showed the intermediate state. Presumably it’s a race condition, the intermediate state is being overwritten before it’s been publishedaraqnid
09/13/2020, 6:03 PMyield()
is enough on my test machineZach Klippenstein (he/him) [MOD]
09/13/2020, 6:07 PMStateFlow
conflates such values, so the intermediate value will never be seen. Steve’s suggestions add a suspend point between the two calls, which gives your collector a chance to resume.Zach Klippenstein (he/him) [MOD]
09/13/2020, 6:09 PMval finishLoad = Job()
…
mutableStateFlow.value = State(true, null)
finishLoad.join()
mutableStateFlow.value = State(false, "name")
…
assertEquals(State(true, null), collectingChannel.receive())
assertTrue(collectingChannel.isEmptyForReceive)
finishLoad.complete()
assertEquals(State(false, "name"), collectingChannel.receive())
assertTrue(collectingChannel.isEmptyForReceive)
Adam Powell
09/13/2020, 6:16 PMShashank
09/13/2020, 7:06 PMZach Klippenstein (he/him) [MOD]
09/13/2020, 8:33 PMZach Klippenstein (he/him) [MOD]
09/13/2020, 8:51 PMShashank
09/13/2020, 10:35 PMState, by nature, doesn’t matter if you conflate it. If you start out in state A, then end up in state C, it doesn’t matter if there was a state B in the middle there somewhereWell, doesn’t this make testing a bit difficult? Let’s say I set
state = State(false, emptyList)
. Then I call a function which sets state = State(true, emptyList)
. The state flow will only give me the second value if there is very little time difference between the two.
So wouldn’t I need to know about the implementation of my SUT and know at which points is the state set without any dealy?Shashank
09/13/2020, 10:38 PMyour best option is to use BroadcastChannel for events.I don’t think it re-emits the latest value to new subscribers. So I can’t really use it for my view state stream.
Adam Powell
09/13/2020, 11:06 PMZach Klippenstein (he/him) [MOD]
09/13/2020, 11:35 PMAnvith
09/14/2020, 3:49 AMAdam Powell
09/14/2020, 1:48 PMAnvith
09/15/2020, 5:10 AM