Aspectos básicos de Kotlin para Android 07.2: DiffUtil y la vinculación de datos con RecyclerView

Este codelab es parte del curso Conceptos básicos de Kotlin para Android. Aprovecharás al máximo este curso si trabajas con los codelabs de forma secuencial. Todos los codelabs del curso se enumeran en la página de destino de los codelabs de Android Kotlin Fundamentals.

Introducción

En el codelab anterior, actualizaste la app de TrackMySleepQuality para mostrar datos sobre la calidad del sueño en un RecyclerView. Las técnicas que aprendiste cuando creaste tu primer RecyclerView son suficientes para la mayoría de los RecyclerViews que muestran listas simples que no son demasiado grandes. Sin embargo, existen varias técnicas que hacen que RecyclerView sea más eficiente para listas grandes y que tu código sea más fácil de mantener y extender para listas y cuadrículas complejas.

En este codelab, compilarás la app de Sleep Tracker del codelab anterior. Aprenderás una forma más eficaz de actualizar la lista de datos de sueño y cómo usar la vinculación de datos con RecyclerView. (Si no tienes la app del codelab anterior, puedes descargar el código de partida para este codelab).

Conocimientos que ya deberías tener

  • Compilar una interfaz de usuario básica con una actividad, fragmentos y vistas
  • Navegar entre fragmentos y usar safeArgs para pasar datos entre fragmentos
  • Ver modelos, fábricas de modelos, transformaciones y LiveData, y sus observadores
  • Cómo crear una base de datos Room, crear un DAO y definir entidades
  • Cómo usar corrutinas para bases de datos y otras tareas de larga duración
  • Cómo implementar un RecyclerView básico con un Adapter, un ViewHolder y un diseño de elemento

Qué aprenderás

  • Cómo usar DiffUtil para actualizar de manera eficiente una lista que muestra RecyclerView
  • Cómo usar la vinculación de datos con RecyclerView
  • Cómo usar adaptadores de vinculación para transformar datos

Actividades

  • Compilar la app de TrackMySleepQuality del codelab anterior de esta serie
  • Actualiza SleepNightAdapter para actualizar la lista de manera eficiente con DiffUtil.
  • Implementa la vinculación de datos para RecyclerView, usando adaptadores de vinculación para transformar los datos.

La app de monitoreo del sueño tiene dos pantallas, representadas por fragmentos, como se muestra en la siguiente figura.

La primera pantalla, que se muestra a la izquierda, tiene botones para iniciar y detener el seguimiento. En la pantalla, se muestran algunos de los datos de sueño del usuario. El botón Borrar borra de forma permanente todos los datos que la app recopiló del usuario. La segunda pantalla, que se muestra a la derecha, es para seleccionar una calificación de la calidad del sueño.

Esta app está diseñada para usar un controlador de IU, ViewModel y LiveData, y una base de datos Room para conservar los datos de sueño.

Los datos de sueño se muestran en un RecyclerView. En este codelab, compilarás la porción de DiffUtil y de vinculación de datos para RecyclerView. Después de este codelab, tu app se verá exactamente igual, pero será más eficiente y más fácil de mantener y escalar.

Puedes seguir usando la app de SleepTracker del codelab anterior o descargar la app de RecyclerViewDiffUtilDataBinding-Starter desde GitHub.

  1. Si es necesario, descarga la app de RecyclerViewDiffUtilDataBinding-Starter de GitHub y abre el proyecto en Android Studio.
  2. Ejecuta la app.
  3. Abre el archivo SleepNightAdapter.kt.
  4. Inspecciona el código para familiarizarte con la estructura de la app. Consulta el siguiente diagrama para ver un resumen del uso de RecyclerView con el patrón de adaptador para mostrar los datos de sueño al usuario.

  • A partir de la entrada del usuario, la app crea una lista de objetos SleepNight. Cada objeto SleepNight representa una sola noche de sueño, su duración y calidad.
  • El SleepNightAdapter adapta la lista de objetos SleepNight en algo que RecyclerView puede usar y mostrar.
  • El adaptador SleepNightAdapter produce ViewHolders que contienen las vistas, los datos y la metainformación para que la vista del reciclador muestre los datos.
  • RecyclerView usa SleepNightAdapter para determinar cuántos elementos hay para mostrar (getItemCount()). RecyclerView usa onCreateViewHolder() y onBindViewHolder() para obtener los titulares de vistas vinculados a los datos para la visualización.

El método notifyDataSetChanged() es ineficiente

Para indicarle a RecyclerView que un elemento de la lista cambió y debe actualizarse, el código actual llama a notifyDataSetChanged() en el SleepNightAdapter, como se muestra a continuación.

var data =  listOf<SleepNight>()
   set(value) {
       field = value
       notifyDataSetChanged()
   }

Sin embargo, notifyDataSetChanged() le indica a RecyclerView que toda la lista podría no ser válida. Como resultado, RecyclerView vuelve a vincular y a dibujar cada elemento de la lista, incluidos los que no se ven en la pantalla. Esto genera mucho trabajo innecesario. En el caso de las listas grandes o complejas, este proceso podría tardar lo suficiente como para que la pantalla parpadee o se trabe mientras el usuario se desplaza por la lista.

Para solucionar este problema, puedes indicarle a RecyclerView exactamente qué cambió. Luego, RecyclerView puede actualizar solo las vistas que cambiaron en la pantalla.

RecyclerView tiene una API enriquecida para actualizar un solo elemento. Podrías usar notifyItemChanged() para indicarle a RecyclerView que un elemento cambió, y podrías usar funciones similares para los elementos que se agregan, quitan o mueven. Podrías hacerlo todo de forma manual, pero esa tarea no sería trivial y podría implicar una gran cantidad de código.

Afortunadamente, existe una mejor manera.

DiffUtil es eficiente y hace el trabajo difícil por ti

RecyclerView tiene una clase llamada DiffUtil que sirve para calcular las diferencias entre dos listas. DiffUtil toma una lista anterior y una nueva, y determina qué cambió. Encuentra los elementos que se agregaron, quitaron o cambiaron. Luego, usa un algoritmo llamado Eugene W. El algoritmo de diferencia de Myers para determinar la cantidad mínima de cambios que se deben realizar en la lista anterior para producir la nueva.

Una vez que DiffUtil descubre qué cambió, RecyclerView puede usar esa información para actualizar solo los elementos que se cambiaron, agregaron, quitaron o movieron, lo que es mucho más eficiente que rehacer toda la lista.

En esta tarea, actualizarás SleepNightAdapter para que use DiffUtil y, así, optimizar RecyclerView para los cambios en los datos.

Paso 1: Implementa SleepNightDiffCallback

Para usar la funcionalidad de la clase DiffUtil, extiende DiffUtil.ItemCallback.

  1. Abre SleepNightAdapter.kt.
  2. Debajo de la definición de clase completa para SleepNightAdapter, crea una nueva clase de nivel superior llamada SleepNightDiffCallback que extienda DiffUtil.ItemCallback. Pasa SleepNight como un parámetro genérico.
class SleepNightDiffCallback : DiffUtil.ItemCallback<SleepNight>() {
}
  1. Coloca el cursor en el nombre de la clase SleepNightDiffCallback.
  2. Presiona Alt+Enter (Option+Enter en Mac) y selecciona Implement Members.
  3. En el diálogo que se abre, haz clic con el botón izquierdo y mantén presionada la tecla Mayúsculas para seleccionar los métodos areItemsTheSame() y areContentsTheSame(), y, luego, haz clic en Aceptar.

    Esto genera stubs dentro de SleepNightDiffCallback para los dos métodos, como se muestra a continuación. DiffUtil usa estos dos métodos para determinar cómo cambiaron la lista y los elementos.
    override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
  1. Dentro de areItemsTheSame(), reemplaza TODO por código que pruebe si los dos elementos SleepNight pasados, oldItem y newItem, son iguales. Si los elementos tienen el mismo nightId, son el mismo elemento, por lo que se devuelve true. De lo contrario, se muestra false. DiffUtil usa esta prueba para ayudar a descubrir si se agregó, quitó o movió un elemento.
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
   return oldItem.nightId == newItem.nightId
}
  1. Dentro de areContentsTheSame(), verifica si oldItem y newItem contienen los mismos datos, es decir, si son iguales. Esta verificación de igualdad revisará todos los campos, ya que SleepNight es una clase de datos. Las clases Data definen automáticamente equals y algunos otros métodos por ti. Si hay diferencias entre oldItem y newItem, este código le indica a DiffUtil que se actualizó el elemento.
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
   return oldItem == newItem
}

Es un patrón común usar un RecyclerView para mostrar una lista que cambia. RecyclerView proporciona una clase de adaptador, ListAdapter, que te ayuda a compilar un adaptador de RecyclerView respaldado por una lista.

ListAdapter hace un seguimiento de la lista por ti y notifica al adaptador cuando se actualiza la lista.

Paso 1: Cambia tu adaptador para que extienda ListAdapter

  1. En el archivo SleepNightAdapter.kt, cambia la firma de la clase SleepNightAdapter para extender ListAdapter.
  2. Si se te solicita, importa androidx.recyclerview.widget.ListAdapter.
  3. Agrega SleepNight como el primer argumento a ListAdapter, antes de SleepNightAdapter.ViewHolder.
  4. Agrega SleepNightDiffCallback() como parámetro al constructor. ListAdapter lo usará para averiguar qué cambió en la lista. La firma de tu clase SleepNightAdapter finalizada debería verse como se muestra a continuación.
class SleepNightAdapter : ListAdapter<SleepNight, SleepNightAdapter.ViewHolder>(SleepNightDiffCallback()) {
  1. Dentro de la clase SleepNightAdapter, borra el campo data, incluido el método setter. Ya no lo necesitas, porque ListAdapter hace un seguimiento de la lista por ti.
  2. Borra la anulación de getItemCount(), ya que ListAdapter implementa este método por ti.
  3. Para deshacerte del error en onBindViewHolder(), cambia la variable item. En lugar de usar data para obtener un item, llama al método getItem(position) que proporciona ListAdapter.
val item = getItem(position)

Paso 2: Usa submitList() para mantener la lista actualizada

Tu código debe indicarle a ListAdapter cuándo hay una lista modificada disponible. ListAdapter proporciona un método llamado submitList() para indicarle a ListAdapter que hay una versión nueva de la lista disponible. Cuando se llama a este método, ListAdapter compara la lista nueva con la anterior y detecta los elementos que se agregaron, quitaron, movieron o cambiaron. Luego, ListAdapter actualiza los elementos que muestra RecyclerView.

  1. Abre SleepTrackerFragment.kt.
  2. En onCreateView(), en el observador de sleepTrackerViewModel, busca el error en el que se hace referencia a la variable data que borraste.
  3. Reemplaza adapter.data = it por una llamada a adapter.submitList(it). El código actualizado se muestra a continuación.

sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
   it?.let {
       adapter.submitList(it)
   }
})
  1. Ejecuta tu app. Se ejecutará más rápido, aunque tal vez no lo notes si tu lista es pequeña.

En esta tarea, usarás la misma técnica que en los codelabs anteriores para configurar la vinculación de datos y eliminarás las llamadas a findViewById().

Paso 1: Agrega la vinculación de datos al archivo de diseño

  1. Abre el archivo de diseño list_item_sleep_night.xml en la pestaña Texto.
  2. Coloca el cursor en la etiqueta ConstraintLayout y presiona Alt+Enter (Option+Enter en Mac). Se abrirá el menú de intención (el menú de "corrección rápida").
  3. Selecciona Convert to data binding layout. Esto ajusta el diseño en <layout> y agrega una etiqueta <data> dentro.
  4. Si es necesario, desplázate hacia arriba y, dentro de la etiqueta <data>, declara una variable llamada sleep.
  5. Haz que su type sea el nombre completamente calificado de SleepNight, com.example.android.trackmysleepquality.database.SleepNight. La etiqueta <data> terminada debería verse como se muestra a continuación.
   <data>
        <variable
            name="sleep"
            type="com.example.android.trackmysleepquality.database.SleepNight"/>
    </data>
  1. Para forzar la creación del objeto Binding, selecciona Build > Clean Project y, luego, Build > Rebuild Project. (Si sigues teniendo problemas, selecciona File > Invalidate Caches / Restart). El objeto de vinculación ListItemSleepNightBinding, junto con el código relacionado, se agrega a los archivos generados del proyecto.

Paso 2: Expande el diseño del elemento con la vinculación de datos

  1. Abre SleepNightAdapter.kt.
  2. En la clase ViewHolder, busca el método from().
  3. Borra la declaración de la variable view.

Código para borrar:

val view = layoutInflater
       .inflate(R.layout.list_item_sleep_night, parent, false)
  1. Donde estaba la variable view, define una variable nueva llamada binding que expanda el objeto de vinculación ListItemSleepNightBinding, como se muestra a continuación. Realiza la importación necesaria del objeto de vinculación.
val binding =
ListItemSleepNightBinding.inflate(layoutInflater, parent, false)
  1. Al final de la función, en lugar de devolver el view, devuelve binding.
return ViewHolder(binding)
  1. Para deshacerte del error, coloca el cursor sobre la palabra binding. Presiona Alt+Enter (Option+Enter en Mac) para abrir el menú de intención.
  1. Selecciona Change parameter 'itemView' type of primary constructor of class 'ViewHolder' to 'ListItemSleepNightBinding'. Esto actualiza el tipo de parámetro de la clase ViewHolder.

  1. Desplázate hacia arriba hasta la definición de la clase ViewHolder para ver el cambio en la firma. Verás un error para itemView, ya que cambiaste itemView por binding en el método from().

    En la definición de la clase ViewHolder, haz clic con el botón derecho en una de las ocurrencias de itemView y selecciona Refactor > Rename. Cambia el nombre a binding.
  2. Antepón val al parámetro del constructor binding para convertirlo en una propiedad.
  3. En la llamada a la clase principal, RecyclerView.ViewHolder, cambia el parámetro de binding a binding.root. Debes pasar un View, y binding.root es el ConstraintLayout raíz en el diseño de tu elemento.
  4. La declaración de clase finalizada debería tener el siguiente aspecto:
class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root){

También verás un error en las llamadas a findViewById(), que corregirás a continuación.

Paso 3: Reemplaza findViewById()

Ahora puedes actualizar las propiedades sleepLength, quality y qualityImage para usar el objeto binding en lugar de findViewById().

  1. Cambia las inicializaciones de sleepLength, qualityString y qualityImage para usar las vistas del objeto binding, como se muestra a continuación. Después de esto, tu código no debería mostrar más errores.
val sleepLength: TextView = binding.sleepLength
val quality: TextView = binding.qualityString
val qualityImage: ImageView = binding.qualityImage

Con el objeto de vinculación en su lugar, ya no necesitas definir las propiedades sleepLength, quality y qualityImage. DataBinding almacenará en caché las búsquedas, por lo que no es necesario declarar estas propiedades.

  1. Haz clic con el botón derecho en los nombres de las propiedades sleepLength, quality y qualityImage. Selecciona Refactor > Inline o presiona Control+Command+N (Option+Command+N en Mac).
  2. Ejecuta tu app. (Es posible que debas limpiar y volver a compilar tu proyecto si tiene errores).

En esta tarea, actualizarás tu app para que use la vinculación de datos con adaptadores de vinculación para establecer los datos en tus vistas.

En un codelab anterior, usaste la clase Transformations para tomar LiveData y generar cadenas con formato para mostrar en vistas de texto. Sin embargo, si necesitas vincular diferentes tipos o tipos complejos, puedes proporcionar adaptadores de vinculación para ayudar a la vinculación de datos a usar esos tipos. Los adaptadores de vinculación son adaptadores que toman tus datos y los adaptan a algo que la vinculación de datos puede usar para vincular una vista, como texto o una imagen.

Implementarás tres adaptadores de vinculación, uno para la imagen de calidad y uno para cada campo de texto. En resumen, para declarar un adaptador de vinculación, debes definir un método que tome un elemento y una vista, y anotarlo con @BindingAdapter. En el cuerpo del método, implementa la transformación. En Kotlin, puedes escribir un adaptador de vinculación como una función de extensión en la clase de vista que recibe los datos.

Paso 1: Crea adaptadores de vinculación

Ten en cuenta que deberás importar varias clases en el paso, y no se llamarán de forma individual.

  1. Abre SleepNightAdapater.kt.
  2. Dentro de la clase ViewHolder, busca el método bind() y recuerda lo que hace. Tomarás el código que calcula los valores de binding.sleepLength, binding.quality y binding.qualityImage, y lo usarás dentro del adaptador. (Por ahora, deja el código como está; lo moverás en un paso posterior).
  3. En el paquete sleeptracker, crea y abre un archivo llamado BindingUtils.kt.
  4. Declara una función de extensión en TextView, llamada setSleepDurationFormatted, y pasa un SleepNight. Esta función será tu adaptador para calcular y dar formato a la duración del sueño.
fun TextView.setSleepDurationFormatted(item: SleepNight) {}
  1. En el cuerpo de setSleepDurationFormatted, vincula los datos a la vista como lo hiciste en ViewHolder.bind(). Llama a convertDurationToFormatted() y, luego, establece el text del TextView en el texto con formato. (Como esta es una función de extensión en TextView, puedes acceder directamente a la propiedad text).
text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources)
  1. Para informar a la vinculación de datos sobre este adaptador de vinculación, anota la función con @BindingAdapter.
  2. Esta función es el adaptador para el atributo sleepDurationFormatted, por lo que debes pasar sleepDurationFormatted como argumento a @BindingAdapter.
@BindingAdapter("sleepDurationFormatted")
  1. El segundo adaptador establece la calidad del sueño según el valor de un objeto SleepNight. Crea una función de extensión llamada setSleepQualityString() en TextView y pasa un SleepNight.
  2. En el cuerpo, vincula los datos a la vista como lo hiciste en ViewHolder.bind(). Llama a convertNumericQualityToString y configura text.
  3. Anota la función con @BindingAdapter("sleepQualityString").
@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight) {
   text = convertNumericQualityToString(item.sleepQuality, context.resources)
}
  1. El tercer adaptador de vinculación establece la imagen en una vista de imagen. Crea la función de extensión en ImageView, llama a setSleepImage y usa el código de ViewHolder.bind(), como se muestra a continuación.
@BindingAdapter("sleepImage")
fun ImageView.setSleepImage(item: SleepNight) {
   setImageResource(when (item.sleepQuality) {
       0 -> R.drawable.ic_sleep_0
       1 -> R.drawable.ic_sleep_1
       2 -> R.drawable.ic_sleep_2
       3 -> R.drawable.ic_sleep_3
       4 -> R.drawable.ic_sleep_4
       5 -> R.drawable.ic_sleep_5
       else -> R.drawable.ic_sleep_active
   })
}

Paso 2: Actualiza SleepNightAdapter

  1. Abre SleepNightAdapter.kt.
  2. Borra todo lo que haya en el método bind(), ya que ahora puedes usar la vinculación de datos y tus nuevos adaptadores para hacer este trabajo por ti.
fun bind(item: SleepNight) {
}
  1. Dentro de bind(), asigna la suspensión a item, ya que debes informar al objeto de vinculación sobre tu nuevo SleepNight.
binding.sleep = item
  1. Debajo de esa línea, agrega binding.executePendingBindings(). Esta llamada es una optimización que le solicita a la vinculación de datos que ejecute de inmediato cualquier vinculación pendiente. Siempre es una buena idea llamar a executePendingBindings() cuando usas adaptadores de vinculación en un RecyclerView, ya que puede acelerar ligeramente el ajuste de tamaño de las vistas.
 binding.executePendingBindings()

Paso 3: Agrega vinculaciones al diseño XML

  1. Abre list_item_sleep_night.xml.
  2. En el ImageView, agrega una propiedad app con el mismo nombre que el adaptador de vinculación que establece la imagen. Pasa la variable sleep, como se muestra a continuación.

    Esta propiedad crea la conexión entre la vista y el objeto de vinculación a través del adaptador. Cada vez que se haga referencia a sleepImage, el adaptador adaptará los datos del SleepNight.
app:sleepImage="@{sleep}"
  1. Haz lo mismo para las vistas de texto sleep_length y quality_string. Cada vez que se haga referencia a sleepDurationFormatted o sleepQualityString, los adaptadores adaptarán los datos de SleepNight.
app:sleepDurationFormatted="@{sleep}"
app:sleepQualityString="@{sleep}"
  1. Ejecuta tu app. Funciona exactamente igual que antes. Los adaptadores de vinculación se encargan de todo el trabajo de formato y actualización de las vistas a medida que cambian los datos, lo que simplifica el ViewHolder y le da al código una estructura mucho mejor que la que tenía antes.

Mostraste la misma lista en los últimos ejercicios. Esto es intencional para mostrarte que la interfaz Adapter te permite diseñar tu código de muchas maneras diferentes. Cuanto más complejo sea tu código, más importante será que lo diseñes bien. En las apps de producción, estos y otros patrones se usan con RecyclerView. Todos los patrones funcionan y cada uno tiene sus beneficios. La que elijas dependerá de lo que estés creando.

¡Felicitaciones! En este punto, estás en buen camino para dominar RecyclerView en Android.

Proyecto de Android Studio: RecyclerViewDiffUtilDataBinding.

DiffUtil:

  • RecyclerView tiene una clase llamada DiffUtil que sirve para calcular las diferencias entre dos listas.
  • DiffUtil tiene una clase llamada ItemCallBack que extiendes para determinar la diferencia entre dos listas.
  • En la clase ItemCallback, debes anular los métodos areItemsTheSame() y areContentsTheSame().

ListAdapter:

  • Para obtener administración de listas de forma gratuita, puedes usar la clase ListAdapter en lugar de RecyclerView.Adapter. Sin embargo, si usas ListAdapter, debes escribir tu propio adaptador para otros diseños, por lo que este codelab te muestra cómo hacerlo.
  • Para abrir el menú de intención en Android Studio, coloca el cursor en cualquier elemento de código y presiona Alt+Enter (Option+Enter en Mac). Este menú es particularmente útil para refactorizar código y crear stubs para implementar métodos. El menú es contextual, por lo que debes colocar el cursor exactamente para obtener el menú correcto.

Vinculación de datos:

  • Usa la vinculación de datos en el diseño del elemento para vincular datos a las vistas.

Adaptadores de vinculación:

  • Anteriormente, usaste Transformations para crear cadenas a partir de datos. Si necesitas vincular datos de tipos diferentes o complejos, proporciona adaptadores de vinculación para ayudar a la vinculación de datos a usarlos.
  • Para declarar un adaptador de vinculación, define un método que tome un elemento y una vista, y anota el método con @BindingAdapter. En Kotlin, puedes escribir el adaptador de vinculación como una función de extensión en View. Pasa el nombre de la propiedad que adapta el adaptador. Por ejemplo:
@BindingAdapter("sleepDurationFormatted")
  • En el diseño XML, establece una propiedad app con el mismo nombre que el adaptador de vinculación. Pasa una variable con los datos. Por ejemplo:
.app:sleepDurationFormatted="@{sleep}"

Cursos de Udacity:

Documentación para desarrolladores de Android:

Otros recursos:

En esta sección, se enumeran las posibles actividades para el hogar para los alumnos que trabajan en este codelab como parte de un curso dirigido por un instructor. Depende del instructor hacer lo siguiente:

  • Si es necesario, asigna una tarea.
  • Comunicarles a los alumnos cómo enviar las actividades para el hogar.
  • Califica las actividades para el hogar.

Los instructores pueden usar estas sugerencias en la medida que quieran y deben asignar cualquier otra actividad para el hogar que consideren apropiada.

Si estás trabajando en este codelab por tu cuenta, usa estas actividades para el hogar para probar tus conocimientos.

Responde estas preguntas:

Pregunta 1

¿Cuáles de las siguientes son necesarias para usar DiffUtil? Selecciona todas las opciones que correspondan.

▢ Extiende la clase ItemCallBack.

▢ Anula areItemsTheSame().

▢ Anula areContentsTheSame().

▢ Usa la vinculación de datos para hacer un seguimiento de las diferencias entre los elementos.

Pregunta 2

¿Cuáles de las siguientes afirmaciones sobre los adaptadores de vinculación son verdaderas?

▢ Un adaptador de vinculación es una función anotada con @BindingAdapter.

▢ El uso de un adaptador de vinculación te permite separar el formato de datos del contenedor de vistas.

▢ Debes usar un RecyclerViewAdapter si quieres utilizar adaptadores vinculantes.

▢ Los adaptadores de vinculación son una buena solución cuando necesitas transformar datos complejos.

Pregunta 3

¿Cuándo deberías considerar usar Transformations en lugar de un adaptador de vinculación? Selecciona todas las opciones que correspondan.

▢ Tus datos son simples.

▢ Estás dando formato a una cadena.

▢ Tu lista es muy larga.

▢ Tu ViewHolder solo contiene una vista.

Comienza la siguiente lección: 7.3: GridLayout con RecyclerView