RecyclerView — ce que c'est, ViewHolder et Adapter dans Android

Auteur : IT Sectr Publié le : 2026-02-23 Temps de lecture : 8 min

RecyclerView est un composant Android Jetpack pour afficher efficacement de grands ensembles de données sous forme de listes et de grilles. Contrairement à ListView, RecyclerView réutilise les ViewHolders et gère la disposition via LayoutManager. Selon Google (Android Developers, 2026), RecyclerView traite jusqu'à 60 images par seconde lors du défilement d'une liste de plus de 1000 éléments grâce au pool de ViewHolders et à l'algorithme de différences DiffUtil. En savoir plus sur l'architecture des applications Android dans notre article sur ListView.

Points clés

  • RecyclerView est un composant moderne pour les listes dans Android, remplaçant ListView dans Android 5.0 (API 21).
  • ViewHolder est un modèle pour mettre en cache les références de View, accélérant la réutilisation des cellules lors du défilement.
  • Adapter est le lien entre les données et RecyclerView, responsable de la création des ViewHolders et de la liaison des données.
  • LayoutManager définit le positionnement des éléments : liste verticale/horizontale (LinearLayoutManager), grille (GridLayoutManager), en escalier (StaggeredGridLayoutManager).
  • DiffUtil est un utilitaire pour calculer la différence entre les listes ancienne et nouvelle, minimisant le redessin des éléments.

Qu'est-ce que RecyclerView ?

RecyclerView est un composant de la bibliothèque Android Jetpack, présenté à Google I/O 2014 dans le cadre d'Android Support Library v7. Il est conçu pour afficher des listes et grilles dynamiques avec des performances élevées. RecyclerView est apparu comme un remplacement de ListView et résout le problème clé de son prédécesseur — l'absence de réutilisation forcée des ViewHolders.

L'architecture de RecyclerView repose sur le modèle Model-View-Adapter : les données sont stockées dans un modèle (List, LiveData, Flow), le rendu est géré par l'Adapter et la disposition est contrôlée par LayoutManager. Chaque composant est responsable de son domaine, rendant le système flexible et extensible.

Selon une enquête d'Android Developers (2025), RecyclerView est utilisé dans 78% des applications Android du top 100 du Google Play. Les performances de défilement pour une liste de plus de 1000 éléments restent stables à 60 FPS sur les appareils de milieu de gamme grâce à trois mécanismes : le pool de ViewHolders, le calcul de mise à jour basé sur les différences et le chargement asynchrone des données.

Quand utiliser RecyclerView

RecyclerView est optimal pour : les listes avec un nombre inconnu d'éléments (flux, chats, journaux), les grilles à N colonnes (galeries, catalogues), les dispositions en escalier (tableaux Pinterest) et les listes avec animations d'ajout/suppression. Pour les écrans simples avec 2 à 5 éléments, LinearLayout ou ScrollView sont plus simples et efficaces — RecyclerView ajoute une surcharge.

Configuration de la dépendance

Pour utiliser RecyclerView, ajoutez la dépendance à build.gradle (app) : implementation 'androidx.recyclerview:recyclerview:1.4.0'. La version minimale de l'API est 14 (Android 4.0). À partir d'AndroidX RecyclerView 1.3.0, les modules recyclerview-selection pour la sélection d'éléments et recyclerview-swipe pour les gestes de balayage sont disponibles.

Comment fonctionne RecyclerView : trois composants clés

RecyclerView est divisé en trois couches indépendantes : l'Adapter gère les données et les ViewHolders, le LayoutManager s'occupe du positionnement des éléments et l'ItemAnimator contrôle les animations. Cette architecture permet de remplacer n'importe quelle couche sans modifier les autres — par exemple, passer de LinearLayoutManager à GridLayoutManager sans changer le code de l'Adapter.

ComposantResponsabilitésImplémentation
AdapterCréer des ViewHolders, lier les données à la View, notifier les changementsRecyclerView.Adapter<VH>
ViewHolderMettre en cache les références de View, éviter findViewById()RecyclerView.ViewHolder
LayoutManagerPositionner les éléments, déterminer la direction de défilementLinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager
ItemAnimatorAnimation pour ajouter, supprimer, déplacer des élémentsDefaultItemAnimator
ItemDecorationDessiner des séparateurs, espacements, fonds entre les élémentsRecyclerView.ItemDecoration

Cycle de travail : (1) L'Adapter crée un ViewHolder via onCreateViewHolder(), (2) LayoutManager détermine la position du nouveau View à l'écran, (3) L'Adapter lie les données via onBindViewHolder(), (4) lors du défilement, les ViewHolders qui sortent de l'écran entrent dans le pool (RecycledViewPool) pour être réutilisés. Au lieu de créer de nouveaux Views, ceux existants sont réutilisés — c'est le mécanisme de performance clé.

Implémentation de ViewHolder dans RecyclerView

ViewHolder est une classe qui stocke les références aux Views (TextView, ImageView, etc.) à l'intérieur d'un élément de liste. Sans ViewHolder, chaque défilement déclencherait findViewById() — l'une des opérations les plus coûteuses de l'interface Android. ViewHolder élimine cet appel en mettant en cache les références après la liaison initiale.

kotlin
// Modèle de données
data class Article(
    title: String,
    summary: String,
    author: String,
    imageUrl: String?
)

// ViewHolder — stocke les références de View
class ArticleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    private val titleText = itemView.findViewById<TextView>(R.id.tvTitle)
    private val summaryText = itemView.findViewById<TextView>(R.id.tvSummary)
    private val authorText = itemView.findViewById<TextView>(R.id.tvAuthor)

    fun bind(article: Article) {
        titleText.text = article.title
        summaryText.text = article.summary
        authorText.text = article.author
    }
}

Règle pratique : chaque View dans la disposition de l'élément doit être déclarée comme propriété ViewHolder avec findViewById() exactement une fois — dans le constructeur. La méthode bind() n'appelle pas findViewById(), elle définit seulement le texte, les couleurs et les écouteurs. Cette approche accélère le défilement de la liste de 30 à 50% selon Google (Android Performance Patterns, 2025).

Types de LayoutManager : choisir la disposition des éléments

LayoutManager définit comment les éléments sont positionnés à l'intérieur de RecyclerView. Android fournit trois implémentations par défaut : LinearLayoutManager, GridLayoutManager et StaggeredGridLayoutManager. Le choix du LayoutManager affecte la perception des données et les performances de défilement.

LayoutManagerDispositionQuand l'utiliserMéthode de configuration
LinearLayoutManagerListe (verticale ou horizontale)Flux, chats, notifications, listes de produitsLinearLayoutManager(context)
GridLayoutManagerGrille à N colonnesGaleries, catalogues, icônes, grilles d'imagesGridLayoutManager(context, spanCount)
StaggeredGridLayoutManagerGrille en escalier (hauteurs d'éléments différentes)Tableaux Pinterest, notes, galeries masonryStaggeredGridLayoutManager(spanCount, orientation)
kotlin
// Configurer LinearLayoutManager dans Fragment
class ArticleListFragment : Fragment() {
    private lateinit var binding: FragmentArticleListBinding

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val recyclerView = binding.recyclerView
        recyclerView.layoutManager = LinearLayoutManager(requireContext())
        recyclerView.adapter = ArticleAdapter(articlesList)

        // Optimisation : taille fixe + pool
        recyclerView.setHasFixedSize(true)
        recyclerView.setItemViewCacheSize(20)

        // Séparateur entre les éléments
        val divider = DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)
        recyclerView.addItemDecoration(divider)
    }
}

Performances : LinearLayoutManager avec défilement vertical est l'option la plus rapide car les éléments sont disposés séquentiellement et LayoutManager calcule les positions en O(1). GridLayoutManager nécessite des calculs supplémentaires pour la division en colonnes mais reste performant avec un spanCount fixe. StaggeredGridLayoutManager est le plus lent des trois car il doit calculer la position des éléments en cascade en tenant compte des hauteurs des éléments voisins. Utilisez-le uniquement lorsque des hauteurs de cellule visuellement différentes sont nécessaires.

Adapter et DiffUtil : mise à jour efficace des données

Adapter dans RecyclerView implémente le modèle Adapter du GoF : il transforme les données (List<T>) en ViewHolders affichés à l'écran. Lorsque les données changent, l'Adapter peut notifier RecyclerView via notifyDataSetChanged(), notifyItemInserted() et des méthodes similaires. Le problème est que notifyDataSetChanged() redessine tous les éléments visibles, provoquant des à-coups (jank).

kotlin
// Adapter avec DiffUtil pour des mises à jour efficaces
class ArticleAdapter : RecyclerView.Adapter<ArticleViewHolder>() {

    private var articles: List<Article> = emptyList()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_article, parent, false)
        return ArticleViewHolder(view)
    }

    override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
        holder.bind(articles[position])
    }

    override fun getItemCount(): Int = articles.size

    // Mettre à jour la liste via DiffUtil
    fun updateArticles(newArticles: List<Article>) {
        val diffCallback = ArticleDiffCallback(articles, newArticles)
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        articles = newArticles
        diffResult.dispatchUpdatesTo(this)
    }
}

// Callback pour DiffUtil
class ArticleDiffCallback(
    private val oldList: List<Article>,
    private val newList: List<Article>
) : DiffUtil.Callback() {

    override fun getOldListSize() = oldList.size
    override fun getNewListSize() = newList.size

    override fun areItemsTheSame(oldPos: Int, newPos: Int): Boolean {
        return oldList[oldPos].title == newList[newPos].title
    }

    override fun areContentsTheSame(oldPos: Int, newPos: Int): Boolean {
        return oldList[oldPos] == newList[newPos]
    }
}

DiffUtil utilise l'algorithme de différences d'Eugene W. Myers, qui calcule le nombre minimum d'opérations (insérer, supprimer, déplacer, modifier) pour transformer l'ancienne liste en la nouvelle. Pour une liste de 100 éléments, DiffUtil fonctionne en 1 à 5 ms (Google, 2025). Pour les grandes listes (10000+), utilisez AsyncListDiffer ou PagingDataAdapter de la bibliothèque Paging — ils effectuent les calculs dans un thread d'arrière-plan.

RecyclerView vs ListView : comparaison

ListView est le prédécesseur de RecyclerView, introduit dans Android 1.0 (API 1). Il affiche également des listes mais n'impose pas ViewHolder, ne supporte pas LayoutManager et ne peut pas animer les changements. RecyclerView a été conçu comme un remplacement de ListView avec une architecture plus stricte et de meilleures performances.

CritèreRecyclerViewListView
ViewHolderObligatoire (architecture)Recommandé mais pas obligatoire
LayoutManagerSéparation : liste, grille, escalierListe verticale uniquement
Animation des changementsDefaultItemAnimator intégréAucun support intégré
Notification des changementsGranulaire : notifyItemInserted/RemovedSeulement notifyDataSetChanged() pour toute la liste
DiffUtilSupport via DiffUtil.CallbackPas d'équivalent
SéparateursItemDecoration (personnalisé)android:divider (intégré)
Version minimaleAPI 14 (Android 4.0) via AndroidXAPI 1 (toutes versions)

Recommandation de Google (Android Developers, 2026) : utilisez RecyclerView pour tous les nouveaux projets. ListView peut rester dans les bases de code existantes où la migration ne justifie pas le coût. RecyclerView offre de meilleures performances avec 100+ éléments, prend en charge le défilement horizontal et les grilles sans solutions de contournement supplémentaires. Dans Android 15, ListView est officiellement marqué comme partiellement obsolète.

Questions fréquentes

RecyclerView n'affiche pas les éléments — que faire ?

Vérifiez trois conditions : (1) l'Adapter est défini via recyclerView.adapter = adapter, (2) le LayoutManager est défini via recyclerView.layoutManager = LinearLayoutManager(context), (3) la liste de données n'est pas vide et l'Adapter a été notifié (notifyDataSetChanged()). Une erreur typique consiste à définir les données après avoir appelé notifyDataSetChanged(). Les données doivent être assignées avant la notification. Vérifiez la taille de la liste : adapter.itemCount doit être supérieur à 0.

Pourquoi RecyclerView défile-t-il lentement ?

La lenteur lors du défilement (jank) se produit lorsque onBindViewHolder() effectue des opérations lourdes : chargement d'images sans cache, findViewById() dans bind, calculs complexes. Solutions : (1) utilisez Glide ou Coil pour le chargement asynchrone d'images, (2) déplacez tous les appels findViewById() dans le constructeur ViewHolder, (3) pour les calculs de différences, utilisez AsyncListDiffer. Activez le profilage GPU dans Android Studio (Profile GPU Rendering) pour trouver les images lentes.

Comment faire un RecyclerView horizontal ?

Passez l'orientation à LayoutManager : LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false). Le deuxième paramètre est reverseLayout (false = gauche à droite). Pour une grille horizontale, utilisez GridLayoutManager avec orientation horizontale ou un LinearSnapHelper personnalisé pour un défilement paginé. Les listes horizontales conviennent bien aux carrousels de produits, d'images et de catégories.

Comment ajouter un écouteur de clic à un élément RecyclerView ?

RecyclerView n'a pas d'onClickListener intégré (contrairement à ListView avec onItemClickListener). Implémentez-le dans ViewHolder : passez un lambda au constructeur et définissez itemView.setOnClickListener. Exemple : class ArticleViewHolder(itemView: View, val onItemClick: (Article) -> Unit) : RecyclerView.ViewHolder(itemView). Appelez onItemClick(article) dans bind(). Une alternative est d'utiliser RecyclerView.addOnItemTouchListener() pour la gestion des gestes.

Qu'est-ce que RecycledViewPool et comment le configurer ?

RecycledViewPool est un pool interne de ViewHolders devenus invisibles lors du défilement. Au lieu d'être détruits, ils sont conservés dans le pool et réutilisés. Par défaut, le pool stocke 5 ViewHolders de chaque type. Augmentez la taille pour les dispositions complexes : recyclerView.getRecycledViewPool().setMaxRecycledViews(VIEW_TYPE_NORMAL, maxCount). Si un RecyclerView a plusieurs types de View (viewType), le pool maintient des piles séparées pour chacun. Partager un RecycledViewPool entre différents RecyclerViews économise de la mémoire sur les écrans avec des listes imbriquées.

Résumé

  • RecyclerView est un composant moderne d'Android Jetpack pour les listes et grilles avec des performances allant jusqu'à 60 FPS.
  • ViewHolder est un modèle obligatoire pour la mise en cache des Views, éliminant findViewById() à chaque défilement.
  • Adapter gère les données et crée des ViewHolders via onCreateViewHolder et onBindViewHolder.
  • LayoutManager — trois implémentations : LinearLayoutManager (liste), GridLayoutManager (grille), StaggeredGridLayoutManager (escalier).
  • DiffUtil — algorithme pour les mises à jour minimales de liste : redessin granulaire au lieu d'un rafraîchissement complet.
  • RecyclerView est utilisé dans 78% des applications Android du top 100 et est officiellement recommandé par Google à la place de ListView.
  • Les performances de RecyclerView sont obtenues grâce au pool de ViewHolders, aux notifications granulaires et au calcul asynchrone des différences.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi