Usando Flow en un proyecto Android
Antonio Leiva

En el artículo anterior veíamos un ejemplo sobre Flow, pero eran los típicos ejemplos que en el día a día no nos llevan a ninguna parte.

¿Cómo encaja todo esto dentro de una aplicación Android?

Hoy vamos a ver un ejemplo

La App

Vamos a usar de base una aplicación relativamente sencilla, un listado de películas que se recuperan de un servidor y se almacenan en una base de datos.

Esto usando una arquitectura también muy sencilla con un patrón de presentación MVVM y un repository que se encarga de los datos. Si quieres saber más, echa un vistazo a mi artículo sobre Clean Architecture, aunque en este caso me he saltado alguna capa para simplificar el ejemplo.

El repository tiene dos fuentes de datos: el servidor, y la base de datos. Si encuentra datos en la base de datos, devolverá estos, y si no se irá al servidor para buscarlos.

    suspend fun getMovies(): List<Movie> {
        if (localDataSource.isEmpty()) {
            val movies =remoteDataSource.getMovies()
            localDataSource.saveMovies(movies)
        }

        return localDataSource.getMovies()
    }

Todo el código está montado con corrutinas, de ahí que el repositorio sea una función suspend. También se está usando la compatibilidad con corrutinas de Room y de Retrofit.

Creando un Flow

Tal y como está montado el proyecto, no tiene mucho sentido usar un Flow, porque solo vamos a recibir datos una única vez del repositorio.

Flow merece la pena usarlo cuando la fuente de datos está “viva”, en el sentido de que va variando en el tiempo y nosotros queremos escuchar esos cambios.

Así que vamos a hacer un pequeño hack. Vamos a simular con un aleatorio que los valores cambian cada cierto tiempo.

Empezamos creando el Flow. Para devolver un Flow no hace falta usar una función suspend, ya que el Flow no se ejecuta hasta que lo recolectemos, y ahí es donde sí que necesitamos una corrutina.

fun getMovies(): Flow<List<Movie>> = flow {
    ...
}

Ahora tenemos que decirle qué valores emitir. Volvemos a poner el código anterior:

fun getMovies(): Flow<List<Movie>> = flow {
    if (localDataSource.isEmpty()) {
        val movies =
            remoteDataSource.getMovies()
        localDataSource.saveMovies(movies)
    }
    ...
}

Pero en vez del de devolver el resultado, lo emitimos:

fun getMovies(): Flow<List<Movie>> = flow {
    if (localDataSource.isEmpty()) {
        val movies =
            remoteDataSource.getMovies()
        localDataSource.saveMovies(movies)
    }

    emit(localDataSource.getMovies())
}

Ya estaría transformado. Lo único que este Flow solo emite un valor, así que no nos aporta demasiado. Para darle un poco de vidilla, haríamos:

while (true) {
    delay(2000)
    emit(localDataSource.getMovies().shuffled())
}

Y así emitimos valores de forma infinita. No nos tenemos por qué preocupar porque el Flow acabe. Cuando el recolector se desconecte o el scope de la corrutina desaparezca, esta corrutina también se cancelará, ya que delay comprueba si la corrutina está finalizada antes de ejecutarse.

Cómo recolectar los datos del Flow

Ahora tienes dos maneras de hacer esto. La más directa es usar el collect que ya vimos en el artículo anterior:

viewModelScope.launch {
    repository.getMovies().collect { list ->
        _movies.value = list
    }
}

Pero con Android-KTX, tenemos una función que nos permite convertir un Flow en un LiveData. En el build.gradle añade la siguiente dependencia:

implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'

Y a partir de aquí podrás utilizar la función asLiveData() sobre cualquier Flow:

val movies: LiveData<List<Movie>> 
    get() = repository.getMovies().asLiveData()

Ejecuta el proyecto, y mira cómo la App baila 💃

Conclusión

Si te fijas, usar Flow es muy sencillo una vez que tienes todos los conceptos de corrutinas asimilados. El API es tan simple que en unos minutos puedes estar creando tus propios Flows y comunicándote de forma asíncrona con la interfaz de usuario.

Además con las utilidades que incluyen las librerías de Android, trabajar con Flow cada día es más y más fácil.

Pero esto no se queda aquí. En el próximo artículo vamos a ver cómo integrar Room con Flow y haremos un ejemplo sencillo de paginación, para que veas un caso aún más real.

Quizá también te interese…

¿Qué es Kotlin Multiplataforma?

¿Qué es Kotlin Multiplataforma?

En el mundo actual, donde los dispositivos móviles están presentes en nuestra vida diaria, es fundamental para los desarrolladores crear aplicaciones que se adapten a diferentes sistemas operativos. Kotlin Multiplataforma es una herramienta que facilita la creación de...

5 trucos de Kotlin para escribir código más eficiente en Android

5 trucos de Kotlin para escribir código más eficiente en Android

El lenguaje de programación Kotlin se ha convertido en el más popular para el desarrollo de aplicaciones de Android en los últimos años. Su sintaxis concisa y moderna, junto con su capacidad para mejorar la eficiencia de código, lo convierten en una opción atractiva...

Cómo crear un backend en Kotlin usando Ktor

Cómo crear un backend en Kotlin usando Ktor

Ktor es un framework de servidor web ligero y rápido para Kotlin, desarrollado por JetBrains. Es ideal para crear aplicaciones web y servicios RESTful, y es muy fácil de usar y configurar. En este artículo, vamos a ver cómo crear un backend para una aplicación de...

0 comentarios

Enviar un comentario

Los datos personales que proporciones a través de este formulario quedarán registrados en un fichero de DevExpert, S.L.U., con el fin de gestionar los comentarios que realizas en este blog. La legitimación se realiza a través del consentimiento de la parte interesada. Si no se acepta, no podrás comentar en este blog. Los datos que proporciona solo se utilizan para evitar el correo no deseado y no se usarán para nada más. Puede ejercer los derechos de acceso, rectificación, cancelación y oposición en contacto@devexperto.com.

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Acepto la política de privacidad *