¿Cómo mejorar el rendimiento de RecyclerView en Android usando DiffUtil?

La clase DiffUtil se utiliza para mejorar el rendimiento de RecyclerView . El algoritmo detrás de DiffUtil es que toma dos listas y encuentra diferencias entre las dos y proporciona la lista actualizada como salida. Utiliza el algoritmo de diferencia de Eugene W. Myers para calcular el número mínimo de actualizaciones. En este artículo, veremos sus implementaciones. Tenga en cuenta que vamos a implementar este proyecto utilizando el lenguaje Kotlin

Implementación paso a paso

Paso 1: Crear un nuevo proyecto

Para crear un nuevo proyecto en Android Studio, consulte Cómo crear/iniciar un nuevo proyecto en Android Studio . Tenga en cuenta que seleccione Kotlin como lenguaje de programación.

Paso 2: Agregar dependencia de enlace de vista

Vaya a build.gradle (aplicación) y la siguiente dependencia dentro de la etiqueta de Android y haga clic en sincronizar ahora.

 construir características {

      viewBinding true

  }

Paso 3: Crea una nueva clase modelo

Cree una nueva clase Language.kt . Usaremos datos de » Idioma » genérico personalizado para pasar la lista que se mostrará en RecyclerView.

Kotlin

// this is the Language model class
class Language(
    val id : Int =0,
    val name : String ="",
    val exp : String =""
)

Paso 4: cree un nuevo archivo de diseño y asígnele el nombre de archivo single_item.xml

Vaya al archivo single_item.xml y consulte el siguiente código. A continuación se muestra el código para el archivo single_item.xml . Es el diseño de elemento único que usaremos en RecyclerView.

XML

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_marginBottom="10dp"
    android:layout_marginStart="5dp"
    android:layout_marginEnd="5dp"
    android:layout_height="110dp">
  
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
          
        <!--Add image view, We will not set any data here.-->
        <ImageView
            android:id="@+id/iv_language"
            android:layout_width="80dp"
            android:layout_height="90dp"
            android:layout_marginStart="20dp"
            android:layout_marginTop="10dp"
            android:scaleType="fitCenter"
            android:src="@mipmap/ic_launcher"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
          
        <!--Text view for showing the language name-->
        <TextView
            android:id="@+id/tv_lang_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="30dp"
            android:layout_marginTop="30dp"
            android:text="Language"
            android:textSize="16sp"
            android:textStyle="bold"
            app:layout_constraintLeft_toRightOf="@id/iv_language"
            app:layout_constraintTop_toTopOf="parent" />
  
        <!--Text View for showing the exp-->
        <TextView
            android:id="@+id/tv_exp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="Exp : 3 years"
            app:layout_constraintLeft_toLeftOf="@id/tv_lang_name"
            app:layout_constraintTop_toBottomOf="@id/tv_lang_name" />
  
    </androidx.constraintlayout.widget.ConstraintLayout>
  
</com.google.android.material.card.MaterialCardView>

Paso 5: Trabajando con activity_main.xml

Vaya al archivo activity_main.xml y consulte el siguiente código. A continuación se muestra el código para el archivo activity_main.xml. Solo tiene un RecyclerView único que usaremos para mostrar nuestros datos.

XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:background="#F5F8FD"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
  
    <!--Add recycler view to main activity-->
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:listitem="@layout/single_item"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
  
    <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
        android:id="@+id/btn_new_language"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add New Language"
        android:padding="10dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginBottom="20dp"/>
    
</androidx.constraintlayout.widget.ConstraintLayout>

Paso 6: Cree una nueva clase y asígnele el nombre MyDiffUtil.kt

Vaya al archivo MyDiffUtil.kt y escriba el siguiente código. Se agregan comentarios para una mejor comprensión del código.

Kotlin

import androidx.recyclerview.widget.DiffUtil
  
// pass two list one oldList and second newList
class MyDiffUtil(
    private val oldList : List<Language>,
    private val newList : List<Language>
) :DiffUtil.Callback() {
    // implement methods
    override fun getOldListSize(): Int {
        // return oldList size
        return oldList.size
    }
  
    override fun getNewListSize(): Int {
        // return newList size
        return newList.size
    }
  
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        // compare items based on their unique id
        return oldList[oldItemPosition].id == newList[newItemPosition].id
    }
  
    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        // in here compare each item if they are same or different
        // return false if any data is same else return true
        return when{
            oldList[oldItemPosition].id != newList[newItemPosition].id -> false
            oldList[oldItemPosition].name != newList[newItemPosition].name -> false
            oldList[oldItemPosition].exp != newList[newItemPosition].exp -> false
            else -> true
        }
    }
}

Paso 7: Trabajar con la clase Adapter

Cree una nueva clase RvAdapter.kt que actuará como una clase de adaptador para la vista del reciclador. Al usar el enlace de vista, usamos la clase generada del diseño single_item.xml, es decir, SingleItemBinding, para agregar datos y verlos en la vista del reciclador de MainActivity.kt en nuestro caso. Los comentarios se agregan antes del código para una mejor comprensión.

Kotlin

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.geeksforgeeks.rvadapterviewbinding.databinding.SingleItemBinding
  
class RvAdapter() : RecyclerView.Adapter<RvAdapter.ViewHolder>() {
  
    private var oldLanguageList= emptyList<Language>()
    // create an inner class with name ViewHolder
    // It takes a view argument, in which pass the generated class of single_item.xml
    // ie SingleItemBinding and in the RecyclerView.ViewHolder(binding.root) pass it like this
    inner class ViewHolder(val binding: SingleItemBinding) : RecyclerView.ViewHolder(binding.root)
  
    // inside the onCreateViewHolder inflate the view of SingleItemBinding
    // and return new ViewHolder object containing this layout
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = SingleItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return ViewHolder(binding)
    }
  
    // bind the items with each item of the list languageList which than will be
    // shown in recycler view
    // to keep it simple we are not setting any image data to view
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        with(holder){
            with(oldLanguageList[position]){
                binding.tvLangName.text = this.name
                binding.tvExp.text = this.exp
            }
        }
    }
  
    // return the size of languageList
    override fun getItemCount(): Int {
        return oldLanguageList.size
    }
  
    fun setData(newLanguageList : List<Language>){
        val diffUtil = MyDiffUtil(oldLanguageList , newLanguageList)
        // it calculates the different items of the oldLanguageList and newLanguageList
        val diffResult = DiffUtil.calculateDiff(diffUtil)
        // assign oldLanguageList to newLanguageList
        oldLanguageList = newLanguageList
        diffResult.dispatchUpdatesTo(this)
    }
}

Paso 8: trabajar con el archivo MainActivity.kt

Vaya al archivo MainActivity.kt y consulte el siguiente código. A continuación se muestra el código del archivo MainActivity.kt . Se agregan comentarios dentro del código para comprender el código con más detalle.

Kotlin

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import com.geeksforgeeks.rvadapterviewbinding.databinding.ActivityMainBinding
  
class MainActivity : AppCompatActivity() {
  
    // view binding for the activity
    private var _binding : ActivityMainBinding? = null
    private val binding get() = _binding!!
  
    // get reference to the adapter class
    private val rvAdapter by lazy { RvAdapter() }
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        _binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
  
        // define layout manager for the Recycler view
        binding.rvList.layoutManager = LinearLayoutManager(this)
          
        // attach adapter to the recycler view
        binding.rvList.adapter = rvAdapter
  
        // create new objects
        val language1= Language(1,"Java" , "Exp : 3 years")
        val language2=Language(2,"Kotlin" , "Exp : 2 years")
        val language3=Language(3,"Python" , "Exp : 4 years")
  
        // call set data method of adapter class and the list data
        rvAdapter.setData(listOf(language1, language2, language3))
        binding.btnNewLanguage.setOnClickListener {
            // on click of button add one more item to the list
            val language4= Language(4,"CPP" , "Exp : 5 years")
            rvAdapter.setData(listOf(language1,language2,language3,language4))
        }
    }
  
    // on destroy of view make the binding reference to null
    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }
}

Producción:

Publicación traducida automáticamente

Artículo escrito por introidx 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 *