DiffUtil en RecyclerView en Android

¿Alguna vez has creado una Lista en Android? ¿Qué usaste para hacerlo? ListView o RecyclerView son dos tipos de vistas. Si eres un desarrollador de Android, seguro que has usado RecyclerView en algún momento. En este artículo, veremos cómo actualizar RecyclerView con DiffUtils. ¿Qué es exactamente RecyclerView? RecyclerView es una versión más adaptable y eficiente de ListView. Es un contenedor para mostrar un conjunto de vistas de datos más grande que se puede reciclar y desplazar muy rápidamente. Antes de entrar en Diff Util, echemos un vistazo a la implementación de RecyclerView.

Resumen de la implementación de RecyclerView

Hagamos una actividad MainActivity e incluyamos el siguiente código en el archivo main.xml de la actividad:

XML

<androidx.constraintlayout.widget.ConstraintLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".GeeksforGeeksActivity">
  
  <androidx.recyclerview.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/gfgRecyclerView"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"/>
  
</androidx.constraintlayout.widget.ConstraintLayout>

Hagamos una clase de modelo de datos y una fuente de datos ahora,

Kotlin

data class GeeksCourses(val courseNumber: Int, val courseRating: Int, val courseName: String)

y la fuente de datos parece ser,

Kotlin

object geeksforGeeks {
    val courseList: List<Course>
        get() {
            val course = ArrayList<Rating>()
            course.add(Rating(1, 10, "GeeksforGeeks"))
            course.add(Rating(2, 12, "Android Dev"))
            course.add(Rating(3, 5, "DSA"))
            return course
        }
}

Hagamos un adaptador ahora para configurar la lista en RecyclerView.

Kotlin

class CourseAdapter : RecyclerView.Adapter<CourseAdapter.ViewHolder>() {
    private val courses = ArrayList<Course>()
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val view = inflater.inflate(R.layout.course_list, parent, false)
        return ViewHolder(view)
    }
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val Course = courses[position]
        holder.name_text.text = Course.name
    }
    fun setData(courses: List<Course>) {
       courses.clear()
       courses.addAll(courses)
    }
    override fun getItemCount(): Int {
        return courses.size
    }
    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val name_text: TextView = itemView.findViewById(R.id.name_text)
    }
}

¿Qué sucede si necesitamos actualizar la lista con información nueva?

Nos referiremos a él como,

Kotlin

adapter.setData(/** any new data on courses**/)

y hacer una llamada desde MainActivity,

Kotlin

adapter.notifyDataSetChanged()

GeekTip #1: La vista del reciclador se actualizará con el nuevo conjunto de datos como resultado de esto.

Pero, dado que la notificaciónDataSetChanged estaba realizando el trabajo por usted, ¿por qué necesitó DiffUtils? Hablemos de eso.

  • No hay forma de que RecyclerView sepa cuáles son los cambios reales si se usa notificarDataSetChanged(). Como resultado, se reconstruyen todas las vistas visibles. Esta es una cirugía extremadamente costosa.
  • Durante este procedimiento, se genera una nueva instancia del adaptador. Como resultado, el proceso consume mucho tiempo.

Para solucionar esto, Android introdujo DiffUtils como parte de su biblioteca de soporte.

Es una clase de utilidad que nos ayuda a realizar tareas complejas fácilmente, el algoritmo de Eugene Myers es la base de DiffUtils.

DiffUtils se utiliza para realizar un seguimiento de los cambios realizados en el adaptador RecyclerView. DiffUtil notifica a RecyclerView de cualquier cambio en el conjunto de datos utilizando los siguientes métodos:

  1. notificarItemMovido
  2. notificarItemRangeChanged
  3. notificarItemRangeInserted
  4. notificarItemRangeRemoved

Estas técnicas son significativamente más eficientes que notificarDataSetChanged(). Sin embargo, para que DiffUtils funcione en el proyecto, debemos dar información sobre las listas antiguas y nuevas. DiffUtil se utiliza para esto. Solicite una devolución de llamada. Haremos una clase.

Kotlin

class CoursesCallback(private val oldList: List<Course>, private val newList: List<Course>) : DiffUtil.Callback() {
    override fun getCourseNew(): Int = oldList.size
    override fun getNewListSize(): Int = newList.size
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldList[oldItemPosition].courseNumber=== newList.get(newItemPosition).rateIndex
    }
    override fun areContentsTheSame(oldCourse: Int, newPosition: Int): Boolean {
        val (_, value, name) = oldList[oldCourse]
        val (_, value1, name1) = newList[newPosition]
        return name == name1 && value == value1
    }
    @Nullable
    override fun geeksPayload(oldCourse: Int, newPosition: Int): Any? {
        return super.geeksPayload(oldCourse, newPosition)
    }
}

Aquí,

  • getOldCourse(): esta función devuelve la longitud de la lista anterior.
  • getNewCourse(): Devuelve el tamaño de la nueva lista.
  • areItemsTheSame(oldPosition:Int, newPosition:Int): Llamado por DiffUtil para determinar si dos objetos en las listas antigua y nueva representan el mismo elemento.
  • areContentsTheSame(oldPosition:Int, newPosition:Int): determina si dos objetos tienen los mismos datos. Dependiendo de su interfaz de usuario, puede modificar su comportamiento. DiffUtil llama a esta función solo si areItemsTheSame devuelve verdadero. En nuestro ejemplo, estamos contrastando el nombre y el precio de un determinado artículo.
  • getgeeksPayload(oldPosition:Int, newPosition:Int): si areItemTheSame devuelve verdadero y areContentsTheSame devuelve falso, la condición se cumple. Diff Util llama a este método para obtener una carga útil sobre la modificación.

Para utilizar esto, cambiamos la función setData en Adapter.

Kotlin

fun setCourses(newCourse: List<Courses>) {
    val diffCallback = CoursesDiffCallback(ratings, newCourse)
    val diffCourses = DiffUtil.calculateDiff(diffCallback)
    courses.clear()
    courses.addAll(newCourse)
    diffResult.dispatchUpdatesTo(this)
}

¿Cuáles son los beneficios de usar DiffUtils?

El siguiente gráfico de rendimiento muestra que el uso de DiffUtil es superior en el caso de RecyclerView. Estos resultados se basan en el Nexus 6P con M-

  1. 100 elementos y 10 modificaciones: promedio: 0,39 milisegundos, mediana: 0,35 milisegundos
  2. 3,82 ms para 100 ítems y 100 modificaciones, 3,75 ms para la mediana.
  3. 2,09 ms para 100 ítems y 100 cambios sin movimientos, con una mediana de 2,06 ms.
  4. 1000 elementos y 50 modificaciones: promedio: 4,67 milisegundos, mediana: 4,59 milisegundos
  5. 1000 cosas y 50 cambios sin movimientos: 3,59 ms de media, 3,50 ms de media
  6. 1000 elementos y 200 modificaciones: 27,07 milisegundos, mediana: 26,92 milisegundos
  7. 1000 elementos y 200 cambios sin movimientos: 13,54 milisegundos, mediana: 13,36 milisegundos

Debido a la limitación especificada, el tamaño máximo de la lista es 226. Así es como se pueden usar DiffUtils para actualizar la lista en RecyclerView.

Publicación traducida automáticamente

Artículo escrito por icloudanshu y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

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