https://kotlinlang.org logo
Title
o

Orhan Tozan

03/18/2020, 10:16 PM
In my ViewModel, when an event listener is triggered:
onUserSelect(userId: Int)
I want it to offer an event to a broadcastchannel named
userSelectEvents: BroadCastChannel<UserSelectEvent>
. The flow
selectedUsers
should depend on this, so I'm probably looking to some kind of building a reducer. This is my idea, is it good?
z

Zach Klippenstein (he/him) [MOD]

03/18/2020, 11:08 PM
sounds fine, this is a super common pattern
o

Orhan Tozan

03/18/2020, 11:35 PM
So let's say we have the following:
class ViewModel {
    val selectedUserIds: Flow<List<Int>> = ...
    fun onUserSelect(userId: Int) {
        ...
    }
}
How would you implement this?
z

Zach Klippenstein (he/him) [MOD]

03/18/2020, 11:44 PM
What’s the relationship between
onUserSelect
and the lists emitted from
selectedUserIds
? Do newly-selected IDs just get appended to the list?
o

Orhan Tozan

03/18/2020, 11:46 PM
Yes, correct.
z

Zach Klippenstein (he/him) [MOD]

03/18/2020, 11:57 PM
you’d probably want a
ConflatedBroadcastChannel
, since it lets you access the current value (
value
property). Then you can just get the current list, append, and offer the new list.
o

Orhan Tozan

03/19/2020, 12:02 AM
Ah didn't see the value property. But wouldn't it be cleaner and more declarative if the onUserSelect method did something like selectUserEvents.offer(Event(id)). Then: `selectedUserIds = selectUserEvents.map { userEventsToSelectedUserIds(it) }
z

Zach Klippenstein (he/him) [MOD]

03/19/2020, 12:30 AM
what does
userEventsToSelectedUserIds
do? how are you accumulating the list of user IDs?
o

Orhan Tozan

03/19/2020, 2:29 PM
Nevermind that, your first suggestion does the trick well.
Let's say we now have a
onSaveButtonClick()
method that sends a network call with the
selectedUserIds
. Should I get it's value by using the
.value
of the
ConflatedBroadcastChannel
or should I launch a coroutine and call
.collect
on the
Flow
?
z

Zach Klippenstein (he/him) [MOD]

03/19/2020, 2:53 PM
Is this method also in your ViewModel? If so then using the value property would be the most straightforward and communicate your intent clearly. If not, you can get the latest value using
selectedUserIds.first()
.
o

Orhan Tozan

03/19/2020, 2:54 PM
Yes, copy paste from the channel:
Given the following:
private val _selectedUserIds = ConflatedBroadcastChannel<List<Int>>(emptyList())
private val selectedUserIds: Flow<List<Int>> = _selectedUserIds.asFlow()
A
onSaveButtonClick()
method should send a network call with the value of selectedUserIds Should I get it's value by using the
.value
of the
ConflatedBroadcastChannel
or should I launch a coroutine and call
.collect()
on the
Flow
? What's the difference?
Allright, didn't know the .first() method on Flow
Wouldn't it make more sense to be named as
.last()
, since it represents the last emitted value?
/**
 * The terminal operator that returns the first element emitted by the flow and then cancels flow's collection.
 * Throws [NoSuchElementException] if the flow was empty.
 */
public suspend fun <T> Flow<T>.first(): T {
The doc states here that it returns the first emitted element.