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…

Los 7 mejores cursos online para aprender Android desde cero en 2021

Los 7 mejores cursos online para aprender Android desde cero en 2021

No hay que ser un genio para darse cuenta de que el sector del desarrollo de aplicaciones móviles está en auge y cada vez más gente busca aprender Android para iniciarse en esta profesión. Atraídos, cómo no, por la posibilidad de obtener un empleo estable, (muy) bien...

Kotlin 1.5.0 : Las 5 novedades que puedes empezar a usar hoy

Kotlin 1.5.0 : Las 5 novedades que puedes empezar a usar hoy

Kotlin 1.5.0 ya está aquí, y como siempre trae una serie de novedades que te van a interesar muchísimo. Cabe destacar que a partir de ahora, de acuerdo las nuevas versiones de Kotlin se lanzarán cada 6 meses, independientemente de las nuevas funcionalidades que...

0 comentarios

Enviar un comentario

Los datos personales que proporciones a través de este formulario quedarán registrados en un fichero de Antonio Leiva Gordillo, 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 *