Flows de Kotlin para implementar búsquedas en tiempo real
Antonio Leiva

En Android, los Flows de Kotlin son una manera de representar secuencias de datos asincrónicas que emiten valores de forma continua.

Estos Flows pueden ser útiles en situaciones en las que deseamos escuchar eventos y procesar los resultados de forma asíncrona, como en el caso de una búsqueda en tiempo real.

Implementar búsqueda al escribir sobre un EditText

Para implementar una búsqueda en tiempo real en Android que escuche los eventos de un EditText y evite que se produzcan muchas consultas de búsqueda en un corto período de tiempo, podemos utilizar la función debounce de Kotlin.

Esta función nos permite filtrar eventos que lleguen demasiado rápido uno detrás de otro, permitiéndonos especificar un tiempo mínimo que debe transcurrir entre eventos para que sean emitidos al Flow.

Para utilizar el debounce con los Flows de Kotlin, podemos seguir los siguientes pasos:

Creamos una función de extensión para escuchar los cambios

Creamos una función de extensión sobre la clase EditText que devuelva un Flow con los cambios de texto del EditText.

Podemos hacer esto utilizando el método callbackFlow de Kotlin, que nos permite crear un Flow que se alimenta de callbacks.

fun EditText.textChanges(): Flow<CharSequence> {
    return callbackFlow {
        val textWatcher = object : TextWatcher {
            override fun afterTextChanged(s: Editable?) = Unit

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                // este método se llama cuando el texto está cambiando
                trySend(s) // emitimos el valor al Flow
            }
        }
        addTextChangedListener(textWatcher)
        awaitClose {
            removeTextChangedListener(textWatcher)
        }
    }
}

Emitir valores solo si ha pasado cierto tiempo

Ahora podemos utilizar la función de extensión que hemos creado para obtener un Flow con los cambios de texto del EditText.

A continuación, aplicamos la función debounce al Flow para especificar un tiempo mínimo que debe transcurrir entre eventos para que sean emitidos.

val editText = EditText(context)

editText.textChanges()
    .debounce(500) // espere 500ms sin eventos para emitir el valor
    .onEach { text ->
        println("Texto actual: $text")
    }
    .launchIn(uiScope)

Con esto, cada vez que el usuario cambie el texto del EditText, se emitirá un evento al Flow.

Sin embargo, si el usuario escribe rápidamente y produce varios cambios de texto en menos de 500ms, solo se emitirá el último evento después de que hayan pasado 500ms sin nuevos cambios de texto.

Por último, podemos utilizar el Flow para realizar una búsqueda en tiempo real utilizando una API de búsqueda o cualquier otra lógica de procesamiento que necesitemos. Por ejemplo:

val editText = EditText(context)

editText.textChanges()
    .debounce(500) // espere 500ms sin eventos para emitir el valor
    .map { text -> text.toString() } // convertimos el CharSequence a String
    .filter { text -> text.isNotEmpty() } // filtramos los valores vacíos
    .distinctUntilChanged() // evitamos hacer búsquedas repetidas
    .flatMapLatest { query ->
        searchApi.search(query) // hacemos la búsqueda utilizando la API de búsqueda
            .asFlow() // convertimos el resultado a un Flow
    }
    .onEach { result ->
        println("Resultado de la búsqueda: $result")
    }
    .launchIn(uiScope)

Con esto, cada vez que el usuario escriba en el EditText y hayan pasado 500ms sin nuevos cambios de texto, se realizará una búsqueda utilizando la API de búsqueda y se mostrará el resultado en la consola.

Conclusión

En conclusión, los Flows de Kotlin son una herramienta útil para representar secuencias de datos asincrónicas en Android y pueden ser utilizados para implementar funcionalidades como la búsqueda en tiempo real.

Al utilizar la función debounce, podemos filtrar eventos que lleguen demasiado rápido uno detrás de otro y especificar un tiempo mínimo que debe transcurrir entre eventos para que sean emitidos al Flow.

De esta manera, podemos evitar que se produzcan muchas consultas de búsqueda en un corto período de tiempo y mejorar el rendimiento de nuestra aplicación.

Quizá también te interese…

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...

Cómo simular una base de datos reactiva en Room con Fakes

Cómo simular una base de datos reactiva en Room con Fakes

En el desarrollo de aplicaciones móviles es muy común utilizar bases de datos para almacenar y gestionar la información que se utiliza en la aplicación. En el caso de Android, una de las opciones más populares es Room, una librería de persistencia de datos que...

Kata del TicTacToe en Kotlin

Kata del TicTacToe en Kotlin

Escribe el código para representar una entidad que almacene el tablero de juego del 3 en raya, y que además tenga: Un método move() con 2 parámetros, fila y columna, que permita añadir un movimiento al tablero Un método findWinner(), que devuelva el ganador (X, Y o...

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 *