paint-brush
3 façons rapides d'optimiser RecyclerViewby@azamatnurkhojayev
1,015
1,015

3 façons rapides d'optimiser RecyclerView

Dans cet article, j'aimerais examiner des moyens rapides d'optimiser lors de l'utilisation de RecyclerView. RecyclerView est un composant d'interface utilisateur, c'est-à-dire un élément qui peut être ajouté à l'interface pour afficher facilement une liste.
featured image - 3 façons rapides d'optimiser RecyclerView
Azamat Nurkhojayev HackerNoon profile picture


Salut tout le monde!


Dans cet article, j'aimerais examiner des moyens rapides d'optimiser lors de l'utilisation de RecyclerView.


RecyclerView est un composant d'interface utilisateur, c'est-à-dire un élément qui peut être ajouté à l'interface pour afficher facilement une liste. Il est intégré au code et contient déjà des outils pour afficher, animer et optimiser la liste, et prend également en charge les paramètres de personnalisation.

Les principaux composants de RecyclerView

Pour que RecyclerView fonctionne correctement, vous devez implémenter les composants suivants :

  • RecyclerView , qui doit être ajouté à la mise en page de notre activité ;
  • Adapter , qui contient, traite et associe les données à la liste ;
  • ListAdapter , a mis à jour Adapter et accepte DiffUtil dans le constructeur ;
  • ViewHolder , qui sert à optimiser les ressources et est une sorte de conteneur pour tous les éléments inclus dans la liste ;
  • DiffUtil , qui est utilisé pour optimiser la liste.


Je n'entrerai pas dans les détails de la façon de l'implémenter à partir de zéro, vous pouvez le trouver sur le lien .

Première optimisation de ViewHolder.

Supprimez l’accès aux ressources et la diffusion dans ViewHolder lors de la liaison.


Par exemple, prenons le code ci-dessous :

 data class TrackingUiModel( val id: Long, val title: String, @ColorRes val color: Int, val eventId: Long, val state: TrackingState, val startTime: Long, val endTime: Long, val countTime: Long, val formattedTime: String, ) class TrackingViewHolder(itemView: View): ViewHolder(itemView) { private val binding : TrackingItemBinding by viewBinding() @SuppressLint("SetTextI18n") fun bind(data: TrackingUiModel) { val stateText = when (data.state) { TrackingState.START -> itemView.context.getString(R.string.in_progress) TrackingState.PAUSE -> itemView.context.getString(R.string.pause) else -> { "" } } binding.eventId.text = data.eventId.toString() binding.eventTitle.text = "${data.title} $stateText" binding.eventColor.setBackgroundColor(ContextCompat.getColor(itemView.context, data.color)) binding.countTextView.text = data.formattedTime } }


Chaque fois que la méthode bind est appelée, les appels getString et getColor seront appelés, et toString sera également appelé pour la conversion de chaîne. De cette façon, nous consommons plus de mémoire. Et vous devez vous assurer que la méthode bind est exécutée rapidement et vous devez vous efforcer de vous assurer que la tâche ViewHolder affiche uniquement les éléments de la liste. Pour les optimisations, il est préférable d'obtenir la chaîne eventId , stateText et color dans l'objet TrackingUiModel .


Le code optimisé ressemble maintenant à ceci :

 data class TrackingUiModel( val id: Long, val title: String, val color: Int, val eventId: String, val state: TrackingState, val stateText: String, val startTime: Long, val endTime: Long, val countTime: Long, val formattedTime: String, ) class TrackingViewHolder(itemView: View): ViewHolder(itemView) { private val binding : TrackingItemBinding by viewBinding() fun bind(data: TrackingUiModel) { binding.eventId.text = data.eventId binding.eventTitle.text = "${data.title} ${data.stateText}" binding.eventColor.setBackgroundColor(data.color) binding.countTextView.text = data.formattedTime } }


Nous avons tout pris au-delà du ViewHolder , tout ce dont nous avons besoin et tout prêt sera reçu dans TrackingUiModel .

Deuxièmement, nous utiliserons ListAdapter et DiffUtil.

Si vous utilisez RecyclerView.Adapter , vous devez passer à ListAdapter et utiliser DiffUtil avec.


Par exemple, prenons le code ci-dessous :

 class TrackingAdapter: RecyclerView.Adapter<TrackingViewHolder>(){ private val mItems = mutableListOf<TrackingUiModel>() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TrackingViewHolder { return TrackingViewHolder( LayoutInflater.from(parent.context) .inflate(R.layout.tracking_item, parent, false)) } override fun getItemCount(): Int = mItems.size override fun onBindViewHolder(holder: TrackingViewHolder, position: Int) { holder.bind(mItems[position]) } fun setItems(items: List<TrackingUiModel>){ mItems.clear() mItems.addAll(items) notifyDataSetChanged() } }


Lors de l'ajout d'éléments de liste, l'appel de la méthode setItems efface la liste, ajoute des éléments de liste et appelle enfin notifyDataSetChanged .


Imaginons que nous modifions ou mettons à jour la liste et que la méthode setItems soit appelée à chaque fois ; cela consommera beaucoup de ressources. Pour cette raison, il est préférable d'utiliser ListAdapter et DiffUtil .


Vous trouverez ci-dessous un TrackingAdapter modifié qui implémente ListAdapter et utilise DiffUtil ; dans mon exemple, il s'agit de la classe TrackingDiffCallback .


Pour ajouter une liste, nous utilisons la méthode trackingAdapter.submitList , et sous le capot, l'adaptateur fera tout le travail de mise à jour de la liste pour nous.


 class TrackingAdapter: ListAdapter<TrackingUiModel, TrackingViewHolder>(TrackingDiffCallback()){ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TrackingViewHolder { return TrackingViewHolder( LayoutInflater.from(parent.context) .inflate(R.layout.tracking_item, parent, false)) } override fun onBindViewHolder(holder: TrackingViewHolder, position: Int) { holder.bind(getItem(position)) } }


 class TrackingDiffCallback: DiffUtil.ItemCallback<TrackingUiModel>() { override fun areItemsTheSame(oldItem: TrackingUiModel, newItem: TrackingUiModel): Boolean { return oldItem.id == newItem.id } override fun areContentsTheSame(oldItem: TrackingUiModel, newItem: TrackingUiModel): Boolean { return oldItem == newItem } }


Troisièmement, utilisez la charge utile.

Il existe des cas tels que l'ajout d'éléments de liste aux favoris, la modification d'une image ou la modification d'une autre vue d'un élément de liste. Lorsque des changements se produisent dans tous ces cas, la méthode bind est appelée à nouveau dans le ViewHolder et nous remarquons visuellement la surbrillance de l'élément. Pour éviter que cela ne se produise, la charge utile nous demande de l'aide.


Pour utiliser la charge utile, apportons une modification à ViewHolder , DiffUtil et Adapter .


Dans mon cas, j'apporterai les modifications suivantes.


Dans TrackingViewHolder, nous ajoutons une méthode de liaison avec les données qui doivent être modifiées.

 fun bind(data: TrackingUiModel, newTime: String) { binding.eventId.text = data.eventId binding.eventTitle.text = "${data.title} ${data.stateText}" binding.eventColor.setBackgroundColor(data.color) binding.countTextView.text = newTime }


Dans TrackingDiffCallback , nous remplaçons la méthode getChangePayload et comparons le champ en cours de modification. Dans mon cas, c'est formattedTime .

 override fun getChangePayload(oldItem: TrackingUiModel, newItem: TrackingUiModel): Any? { if (oldItem.formattedTime != newItem.formattedTime) return newItem.formattedTime return super.getChangePayload(oldItem, newItem) }


Dans TrackingListAdapter, nous remplaçons la méthode onBindViewHolder par des charges utiles. Nous vérifions si la charge utile est vide ou non, si elle n'est pas vide, alors nous obtenons le premier élément et appelons la méthode bind pour la charge utile.

 override fun onBindViewHolder(holder: TrackingViewHolder, position: Int, payloads: MutableList<Any>) { if (payloads.isEmpty()) { super.onBindViewHolder(holder, position, payloads) } else { val newTime = payloads.firstOrNull() as? String ?: "" holder.bind(getItem(position), newTime) } } 



Sans charge utile


Avec charge utile



Liens de référence :