KotlinLeaner
02/08/2023, 4:33 PMChannel
Buffer. I am learning to Poll item through Channel
. When I send item, it doesn't receive()
all item. I don't understand why?class QueueViewModel(private val application: Application) : AndroidViewModel(application) {
val basketChannel = Channel<String>(Channel.UNLIMITED)
init {
startPolling()
}
fun addItems() {
addItemInChannel(100L, "Item 1")
addItemInChannel(1000L, "Item 2")
addItemInChannel(400L, "Item 3")
addItemInChannel(500L, "Item 4")
}
fun addItemInChannel(delay: Long, item: String) {
viewModelScope.launch {
delay(delay)
logE("basketChannelItem added -> $item")
basketChannel.send(item)
}
}
fun startPolling() {
viewModelScope.launch {
Log.e(TAG, "Starting Polling")
for (element in basketChannel) {
logE("basketChannel Item poll -> $element")
basketChannel.receive()
}
}
}
}
addItems()
in activity..Casey Brooks
02/08/2023, 4:43 PMfor element in basketChannel
will react once an item is sent to the channel. It’s a push-based mechanism, where items that are sent to the channel cause the receiver to react to the item, as opposed to a “poll” which is a pull-based mechanism
The additional basketChannel.receive
will cause the channel to consume an additional item, effectively consuming 2 items for every 1 iteration, basically dropping every other item in your case (or suspending indefinitely if you do not send an even number of items)Jacob
02/08/2023, 4:43 PMKotlinLeaner
02/08/2023, 4:58 PMJacob
02/08/2023, 5:04 PMfor
body is complete.for in
does. Removes 1 element from the queue processes it (in this case just logs it) then removes the next element. It will keep doing that until something closes the channel. if the channel is empty it will suspend until something is addedKotlinLeaner
02/08/2023, 5:21 PMfor
. from the startPollingCasey Brooks
02/08/2023, 5:22 PMchannel.send()
or channel.trySend()
, an item gets placed into a queue within the channel. That item will stay within that queue until somewhere else, something starts reading from the channel. There are several ways to read values from the channel:
You can implement your own loop and manually call receive()
within the loop:
while(true) {
val item = channel.receive()
handleItem(item)
}
You can use the Channels Iterator
for(item in channel) {
handleItem(item)
}
You can receive the items as a Flow:
channel
.receiveAsFlow()
.onEach { handleItem(it) }
.launchIn(viewModelScope)
All of these mechanisms effectively do the same thing: read items one at a time from the Channel’s queue, suspending until new items are sent. However, they’re not perfectly equivalent. Most notably, the first example (directly calling channel.receive()
) will throw an exception once the channel is closed, while the other two mechanisms (iterator and Flow), will simply stop sending items without throwing an exception. This is why we’re recommending using the Iterator rather than calling channel.receive()
, because it’s more natural to how you would typically use a Channel and you don’t need to worry about handling exceptionschannel.receive()
manually, and using the iterator instead. And more generally, try to understand the ways things are done in Kotlin first, before comparing the Kotlin APIs to Java onesKotlinLeaner
02/08/2023, 6:35 PM