Home > database >  Do Kotlin Flows drop emissions fired in too rapid succession?
Do Kotlin Flows drop emissions fired in too rapid succession?

Time:09-15

I'm writing an Android app that takes screen-touch MotionEvents and converts them into a StateFlow, which is then collected by a Jetpack Compose function that draws them on the screen.

The MotionEvent capture (based around Modifier.motionEventSpy) works as expected, but the resultant Flows frequently don't make it to the Compose function, causing errors, if they're too close together in time.

It happens when two MotionEvents fire almost simulaneously: MotionEvent.ACTION_DOWN and the first MotionEvent.ACTION_MOVE happen in very rapid succession, and perhaps 20 or 30 per cent of the time, the MotionEvent.ACTION_DOWN Flow emission is never collected by the Compose function.

It doesn't happen all the time, or even most of the time, but it happens enough to be a problem.

(Another example of Flow emits not being collected: I've also noticed that, when I have an event listener on exoPlayer, emiting Flows when the exoPlayer state changes, only the second exoPlayer state change ever gets collected if two state changes happen near-simultaneously. For instance, when a media file is played to the very end, exoPlayer's onIsPlayingChanged listener fires at the same time as exoPlayer's onPlaybackStateChanged. If I have both of those listeners emiting on the same StateFlow, only one of them will ever be collected.)

So I'm thinking Kotlin Flows use some sort of mutex lock to prevent two emits/value changes happening at the same time. Is that correct?

And if that's the case, is there anything I do to ensure every Flow.emit or Flow.value = change makes it to the other side??

Are some types of Flows better than others when it comes to concurrency handling?

CodePudding user response:

That is the expected behaviour of state flow. Sadly, the documentation points it out only on the testing section:

https://developer.android.com/kotlin/flow/test#stateflows

Note that this stream of values is conflated, which means that if values are set in a StateFlow rapidly, collectors of that StateFlow are not guaranteed to receive all intermediate values, only the most recent one.

Can you try using flow { } (I inow is cumbersome)? Or maybe can you try with channels (yep you loose the flow advantages)?

  • Related