Kotlin Flow y Websockets con arquitectura limpia en Android
Recientemente, nuestro equipo intentó implementar websockets. Pensamos fácilmente en usar Rx cuando escuchamos eventos, pero me pregunté cómo hacerlo sin él. Así que probamos el famoso Kotlin Flow
, pero no sé si nuestra implementación es correcta.
La arquitectura de nuestra aplicación está dividida en cuatro capas:
– Servicio: emite y recibe eventos del socket.
– Repositorio: filtra, mapea, transforma, etc.
– ViewModel: populan los LiveDatas.
– Actividad: observa los cambios y actualiza la interfaz de usuario.
Por lo tanto, escuchamos los eventos recibidos en el servicio de la siguiente manera:
fun listenMessages(): Flow<><message>> = channelFlow {
socket.on("NewMessage") { args ->
val message = gson.fromJson(args[0].toString(), ...)
trySend(message)
}
awaitClose()
}
Utilizamos la corrutina channelFlow
para enviar al consumidor cuando se recibe un evento con trySend
, y mantenemos este Flow
vivo usando awaitClose
.
El repositorio realiza cierta lógica después de recibir el Flow
y lo envía de vuelta al ViewModel:
fun getMessages(): Flow<><message>> {
return service.listenMessages()
.filter { ... }
.map { ... }
}
Luego, el ViewModel lanza las corrutinas y actualiza el LiveData al recolectar el Flow
:
fun getMessages() {
viewModelScope.launch(context = Dispatcher.IO) {
repository.getMessages()
.collect {
messagesLiveData.postValue(it)
}
}
}
Esto funciona bien, sin embargo, esto plantea algunas preguntas:
– ¿Es esta la implementación correcta?
– ¿Cuando necesitamos escuchar constantemente, es channelFlow
la elección correcta?
– En este caso, ¿deberíamos usar canales clásicos en lugar de Flow
(caliente vs frío)?
Gracias de antemano por sus consejos.
davy.ai
La implementación parece correcta y sigue el enfoque recomendado para usar
Flow
.channelFlow
es una buena elección para escuchar eventos constantemente, ya que proporciona una forma conveniente de emitir eventos tan pronto como se reciben.Si bien
Channel
también se podría usar en este escenario, sería menos eficiente ya que requiere un manejo manual más minucioso de los eventos. Además,Channel
puede tener más errores queFlow
, ya que requiere el uso declose()
para evitar fugas de memoria.En general, usar
Flow
en lugar de RxJava para este tipo de escenario es una excelente opción, ya que ayuda a simplificar el código y reducir la cantidad de código repetitivo necesario para gestionar flujos de eventos.