DEV Community

Jesus Almaral
Jesus Almaral

Posted on

Android: executePendingBindings() en RecyclerViews

Como nada es perfecto, data binding tiene una desventaja con
respecto a findViewById() en Android.

Android “pinta” los views en la pantalla cada 16ms en promedio, esta actualización de la pantalla puede suceder en menos tiempo, pero si se hacen procesos pesados en el hilo principal (Main Thread) podría causar que la actualización sea de más de 16ms y empezamos a ver lags en la pantalla. Cuando usamos binding para asignar valores a un view, por ejemplo al asignar un texto a un TextView con binding.myTextView.text = “Some text”, el binding no se ejecuta al instante, sino que espera a que pase ese tiempo de 16ms para medir cuanto el área del nuevo texto y luego pintarlo. Es como cuando juegas con tu perro a lanzar la pelota y va por ella pero luego no la suelta hasta que pasas un rato tratando de quitársela (16ms en promedio).
Esto por lo general no nos afecta, por ejemplo cuando abrimos una nueva Activity y pintamos todo con binding, 16ms no son nada. Lanzaste la pelota a tu perro una vez y se la quitas, no pasa nada.

Pero ahora imagina un recyclerView con decenas de elementos, cuando haces scroll rápidamente y viene el siguiente elemento, puede ser que todavía no hayan pasado los 16ms recomendados, pero podría suceder que cuando aparece el siguiente elemento el binding no haya alcanzado a medir y pintar el anterior, entonces podrían verse lags extraños. Es como si quisieras romper un record de lanzar pelotas y ya viene la siguiente pero tu perro todavía no suelta la anterior.
Esto es poco común, y de hecho si no implementas lo que estoy a punto de mencionarte muchas veces no tendrás problemas, pero es mejor prevenir.

La solución para prevenir esto es que después de pintar los views de tu ViewHolder, mandes llamar binding.executePendingBindings(), así:

inner class EqViewHolder(private val binding: ItemBinding): RecyclerView.ViewHolder(binding.root) {
    fun bind(earthquake: Earthquake) {
        binding.myTextView.text = someString
        binding.myImageView.src = someImage
        // Más cosas que hagas con tus views
        ... 
        // JUSTO AQUÍ VA 👇
        binding.executePendingBindings()
    }
}
Enter fullscreen mode Exit fullscreen mode

De esta manera, vas a forzar al binding a que no se espere los 16ms, sino que pinte todo inmediatamente. Sencillo, es solo agregar una linea de código, aunque Android no explica mucho para qué sirve en su documentación oficial y por eso a veces es difícil de recordar.

Espero que los de Android manejen esto automáticamente en el futuro. Mientras tanto te invito a dejar tus comentarios.
Como siempre todos los comentarios y dudas son más que bienvenidos. Te invito a visitar mi blog (https://www.hackaprende.com) o mi canal de Youtube para ver más artículos y cursos sobre diseño, programación y emprendimiento tecnológico.

Top comments (0)