https://kotlinlang.org logo
#coroutines
Title
# coroutines
g

gabin

04/20/2020, 5:40 PM
Hi guys. What is the equivalent of “onEachLatest” operator in Flow? I need to cancel previously running suspend fun in onEach block
o

octylFractal

04/20/2020, 5:43 PM
Not sure what operator you're referring to, I can't find that in reactor or rxjava -- but perhaps
collectLatest
is what you want?
Copy code
* The crucial difference from [collect] is that when the original flow emits a new value, [action] block for previous
 * value is cancelled.
m

Marc Knaup

04/20/2020, 5:43 PM
Or
mapLatest
and simply returning the passed value.
Or just copy the implementation of
onEach
and add `Latest`:
Copy code
fun <T> Flow<T>.onEachLatest(action: suspend (T) -> Unit): Flow<T> = transformLatest { value ->
    action(value)
    emit(value)
}
👍 1
g

gabin

04/20/2020, 5:48 PM
collectLatest is not exactly what I need. It’s a suspend function, and I’ve decided to switch to flow.onEach() {} . launchIn(scope) construction
I want to use this kind of pattern:
instead of scope.launch construction:
m

Marc Knaup

04/20/2020, 5:52 PM
And
updateUI
can be safely canceled? If you get too many events you could also use
.conflate()
before
.onEach()
g

gabin

04/20/2020, 5:52 PM
@Marc Knaup thx for your implementation but is it really missing in flow library?
m

Marc Knaup

04/20/2020, 5:52 PM
A lot of operators could be added to the standard library 🙂
g

gabin

04/20/2020, 5:52 PM
yes, updateUI can be canceled
I use debounce() instead of conflate
m

Marc Knaup

04/20/2020, 5:53 PM
You could suggest adding it and provide a use case: https://github.com/Kotlin/kotlinx.coroutines/issues/new
I’m still undecided between
debounce
and
sample
.
debounce
causes an initial delay, doesn’t it?
Oh, but
sample
may be good for events but not for data 😅
A hybrid would be nice.
g

gabin

04/20/2020, 5:54 PM
no,
debounce
takes the recent value in the time range
m

Marc Knaup

04/20/2020, 5:54 PM
Yes, but it waits at least time range for that
So if you debounce 1 second you will get the first update at least in 1 second. That’s how I read the docs. But let me test
g

gabin

04/20/2020, 5:55 PM
e.g. if user types “abcde” I will get value only when he stops typing
m

Marc Knaup

04/20/2020, 5:55 PM
Yeah for typing it makes sense
For button clicks it won’t
g

gabin

04/20/2020, 6:03 PM
@Marc Knaup and what do you think to use for button clicks? simple flow with
collectLatest{}
or
single()
?
m

Marc Knaup

04/20/2020, 6:06 PM
None of the standard operators is suitable 😞
g

gabin

04/20/2020, 6:07 PM
I am wondering what behavior do you want to achieve 😉
m

Marc Knaup

04/20/2020, 6:08 PM
In RxJava it would be
throttleLatest
It would basically prevent two events (e.g. button clicks) that are too close together.
(you can do the same for
onEachLatest
😉)
b

bezrukov

04/20/2020, 7:24 PM
@gabin you can use
mapLatest
as is (according to example you used)
Copy code
events()
   .mapLatest { event -> updateUI(event) }
   .launchIn(scope)
g

gabin

04/20/2020, 7:33 PM
@bezrukov map has slightly different purpose. It converts 1 type to another. I don’t want to achieve this
b

bezrukov

04/20/2020, 7:36 PM
in your case you will convert it to unit, and it doesn't matter. You can review collectLatest implementation, and it's done via mapLatest as well.
👍 2
if naming confuses you, you can add extension
onEachLatest(action: ..) =  mapLatest(action)
g

gabin

04/20/2020, 7:50 PM
ok, thanks for proposition
10 Views