Issue
Let's say we have a Channel
like this
private val channel = Channel<String>(1)
And we are listening to the Channel
elements like this
channel.receiveAsFlow().collect { myStr ->
println(myStr)
}
If I run something like this
private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
...
fun sendMessage(myMessage: String) {
scope.launch {
channel.send(myMessage)
}
}
...
sendMessage("a")
sendMessage("b")
sendMessage("c")
sendMessage("d")
The output is going to be
a
b
c
d
Now, what I'm trying to achieve is that if I send "b"
it delays the processing of the elements in the channel for 1 second.
For example, if I do
...
sendMessage("a")
sendMessage("b")
sendMessage("c")
sendMessage("b")
sendMessage("d")
sendMessage("e")
The output that I would expect would be like
a // prints immediately
b // prints right after a
c // prints after 1 second
b // prints right after c
d // prints after 1 second
e // prints right after d
My question is, how would I achieve this behavior? I've been trying to add delay()
here and there, but I didn't have any luck.
Solution
Here's an idea, but it feels a little hacky to me. trySend
would not work with this. I'm not sure how to make trySend
make sense with your criteria, because it's supposed to return immediately with a result about whether the value posted.
Here, send()
suspends until the possible delay is over. If you don't want to wait for it, you'd have to launch a coroutine each time you send something.
Since the Channel "constructor" is not a true constructor, you can't subclass it. My workaround is to create a class that uses it as a delegate.
val backingChannel = Channel<String>(1)
val channel = object: Channel<String> by backingChannel {
var delayNext = false
val mutex = Mutex()
override suspend fun send(element: String) = mutex.withLock {
if (delayNext) {
delay(1000)
}
delayNext = element == "b"
backingChannel.send(element)
}
}
Answered By - Tenfour04
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.