I have a question around coroutines specifically dealing with needing to listen for a response then send the request. I think an example might be easier then me trying to explain. I am going to use my specific use case, sending and receiving XMPP messages but try to remove some of the extra stuff that doesn’t really matter to the question. Super old way would be to just use listeners and set one up before I send. Its not great but it works.
xmppClient.addPacketListener { packet -> doStuff() } // listen for response
xmppClient.send(Packet()) // send request
With Rx, I usually solve this problem with a merge. I merge two observables, the listener and the deferred send. The deferred send never returns a value so it doesn’t matter what type it is. The merge is just there for ordering events.
val sendPacket = Observable.defer { xmppClient.send(Packet()) }
merge(xmppClient.packets(), sendPacket)
.subscribe { packet ->
doStuff()
}
With coroutines I really don’t know what I am supposed to do to guarantee, no matter what, that I am listening before I send. Right now I have something like
val packetDefered = async { xmppClient.packets() }
yield()
xmppClient.send(Packet())
val packet = packetDefered.await()
The yield was to try and force this coroutine to give up execution so that the async was listening before I sent the packet. Otherwise I might miss the response to my packet. The only other thing I was thinking was that I could try to do something like the merge via awaitAll
val packet = awaitAll(
async {
xmppClient.packets()
},
async {
xmppClient.send(Packet())
null
}
).firstNotNull()
Does anyone have any guidance on what to do here? This is a use case we have all the time. I don’t want to write it some way only to figure out we messed it up in a billion places.