Recently, our team tried to implement websockets. We easily thought to use Rx when listening on events but I wondered how to do without it. So, we tried the famous Kotlin Flow but I don't know if our implementation is correct.
Our app's architecture is splitted in four layers:
- Service - emits and receives events from socket,
- Repository - filters, maps, transforms, etc,
- ViewModel - populates the LiveDatas
- Activity - observes the changes and updates UI.
Therefore, we listen the events received into the Service as follows:
fun listenMessages(): Flow<List<Message>> = channelFlow {
socket.on("NewMessage") { args ->
val message = gson.fromJson(args[0].toString(), ...)
trySend(message)
}
awaitClose()
}
We use channelFlow's coroutine to send to the consumer when an event is received with trySend and we keep this Flow alive by using awaitClose.
The Repository does some logic after catching the Flow and sends it back to the ViewModel:
fun getMessages(): Flow<List<Message>> {
return service.listenMessages()
.filter { ... }
.map { ... }
}
Then, the ViewModel launches the coroutines and updates the LiveData when collecting the Flow:
fun getMessages() {
viewModelScope.launch(context = Dispatcher.IO) {
repository.getMessages()
.collect {
messagesLiveData.postValue(it)
}
}
}
This works well however this raises some questions:
- Is this the correct implementation?
- When we need to constantly listening, does
channelFlowis the right choice? - In this case, should we use classic
Channels instead ofFlow(hot vs cold)?
Thanks in advance for your advices.