-
Notifications
You must be signed in to change notification settings - Fork 22
Channels ‐ Communication between coroutines
Devrath edited this page Dec 23, 2023
·
1 revision
Contents |
---|
Sending & receiving values in channel |
Cancelling a channel |
Closing a channel |
Choosing between close() and cancel() |
Code |
- Whenever we send multiple values using
channel.send()
on the sender side, We need to triggerchannel.recieve()
for the same amount of time on the receiving end. - If say trigger
send()
thrice and haverecieve()
on the receiver only twice, The receiver will not get the third item.
- If we cancel the channel, even if the channel sends new emissions, it is not received by the receiver.
- When the channel is canceled, an exception is thrown and you can also throw a custom exception.
- You can catch the exception, It won't cause a runtime crash of the application.
- Once you cancel the channel, You cannot send and receive the emissions.
- Even if you
send
values after the channel is canceled it won't take any effect. - Invoking cancel() on a coroutine job associated with a channel will cancel the entire coroutine and any ongoing operations within it.
- This includes canceling both the sender and receiver coroutines involved in channel communication.
@HiltViewModel
class ChannelsDemoVm @Inject constructor( ) : ViewModel() {
// A channel of languages
private var languageChannel = Channel<Languages>()
/**
* Canceling a channel
*/
fun cancellingChannel() {
// Co-Routine - 1
viewModelScope.launch {
println("Sending value - 1")
languageChannel.send(Languages.English)
println("Sending value - 2")
languageChannel.send(Languages.Hindi)
println("Sending value - 3")
languageChannel.send(Languages.French)
}
// Co-Routine - 2
viewModelScope.launch {
try {
println(languageChannel.receive())
languageChannel.cancel(CancellationException("Custom Exception"))
println(languageChannel.receive())
println(languageChannel.receive())
}catch (ex : Exception){
println(ex.message)
println("Is it closed for Send: -> "+languageChannel.isClosedForSend)
println("Is it closed for Receive: -> "+languageChannel.isClosedForReceive)
}
}
}
enum class Languages { English , Hindi , French }
}
Sending value - 1
English
Custom Exception
Is it closed for Send: -> true
Is it closed for Receive: -> true
Sending value - 2
- We use close to close the channel when there are no more emissions.
- We try to send emissions once the channel is closed, It will lead to a runtime exception and might cause a crash.
- When a channel is closed, attempts to send further elements will result in an exception (ClosedSendChannelException).
- The receiving side can use the
isClosedForReceive
property to check whether the channel has been closed.
- Depends on the use case
- If you want to explicitly signal the end of data transmission through the channel, allowing the receiver to gracefully handle the termination of communication, use close().
- If you need to abruptly stop the entire coroutine, including both the sender and receiver, use cancel(). This can be useful, for example, when you want to interrupt the coroutine in response to external events or timeouts.
- In many cases, close() is sufficient for signaling the end of communication through the channel. cancel() is more aggressive and can be used when you want to cancel the entire coroutine, including any ongoing operations, due to external conditions or certain constraints in your application logic.
@HiltViewModel
class ChannelsDemoVm @Inject constructor( ) : ViewModel() {
// A channel of languages
private var languageChannel = Channel<Languages>()
/**
* Sending and receiving only one value
*/
fun simpleCommunication() {
// Co-Routine - 1
viewModelScope.launch {
languageChannel.send(Languages.English)
}
// Co-Routine - 2
viewModelScope.launch {
println(languageChannel.receive())
}
}
/**
* Sending and receiving multiple values
*/
fun sendingMultipleValues() {
// Co-Routine - 1
viewModelScope.launch {
languageChannel.send(Languages.English)
languageChannel.send(Languages.Hindi)
languageChannel.send(Languages.French)
}
// Co-Routine - 2
viewModelScope.launch {
languageChannel.consumeEach {
println(languageChannel.receive())
}
}
}
/**
* Canceling a channel
*/
fun cancellingChannel() {
// Co-Routine - 1
viewModelScope.launch {
println("Sending value - 1")
languageChannel.send(Languages.English)
println("Sending value - 2")
languageChannel.send(Languages.Hindi)
println("Sending value - 3")
languageChannel.send(Languages.French)
}
// Co-Routine - 2
viewModelScope.launch {
try {
println(languageChannel.receive())
languageChannel.cancel(CancellationException("Custom Exception"))
println(languageChannel.receive())
println(languageChannel.receive())
}catch (ex : Exception){
println(ex.message)
println("Is it closed for Send: -> "+languageChannel.isClosedForSend)
println("Is it closed for Receive: -> "+languageChannel.isClosedForReceive)
}
}
}
/**
* Closing a channel
*/
fun closingChannel() {
// Co-Routine - 1
viewModelScope.launch {
languageChannel.send(Languages.English)
languageChannel.close()
languageChannel.send(Languages.Hindi)
languageChannel.send(Languages.French)
}
// Co-Routine - 2
viewModelScope.launch {
languageChannel.consumeEach {
println(languageChannel.receive())
}
}
}
enum class Languages { English , Hindi , French }
}