RecyclerView — cosa è, ViewHolder e Adapter in Android

Autore: IT Sectr Pubblicato: 2026-02-23 Tempo di lettura: 8 min

RecyclerView è un componente Android Jetpack per visualizzare efficientemente grandi insiemi di dati sotto forma di elenchi e griglie. A differenza di ListView, RecyclerView riutilizza i ViewHolder e gestisce il layout tramite LayoutManager. Secondo Google (Android Developers, 2026), RecyclerView elabora fino a 60 fotogrammi al secondo durante lo scorrimento di un elenco di oltre 1000 elementi grazie al pooling dei ViewHolder e all'algoritmo di differenze DiffUtil. Ulteriori informazioni sull'architettura delle app Android sono disponibili in il nostro articolo su ListView.

Punti chiave

  • RecyclerView è un componente moderno per elenchi in Android, che ha sostituito ListView in Android 5.0 (API 21).
  • ViewHolder è un pattern per memorizzare nella cache i riferimenti alle View, accelerando il riutilizzo delle celle durante lo scorrimento.
  • Adapter è il collegamento tra i dati e RecyclerView, responsabile della creazione dei ViewHolder e del binding dei dati.
  • LayoutManager definisce il posizionamento degli elementi: elenco verticale/orizzontale (LinearLayoutManager), griglia (GridLayoutManager), a cascata (StaggeredGridLayoutManager).
  • DiffUtil è un'utilità per calcolare la differenza tra elenchi vecchi e nuovi, minimizzando il ridisegno degli elementi.

Cos'è RecyclerView?

RecyclerView è un componente della libreria Android Jetpack, presentato al Google I/O 2014 come parte di Android Support Library v7. È progettato per visualizzare elenchi e griglie dinamiche con alte prestazioni. RecyclerView è nato come sostituto di ListView e risolve il problema principale del suo predecessore — la mancanza di riutilizzo forzato dei ViewHolder.

L'architettura di RecyclerView si basa sul pattern Model-View-Adapter: i dati sono memorizzati in un modello (List, LiveData, Flow), il rendering è gestito dall'Adapter e il layout è controllato da LayoutManager. Ogni componente è responsabile della propria area, rendendo il sistema flessibile ed estensibile.

Secondo un sondaggio di Android Developers (2025), RecyclerView è utilizzato nel 78% delle app Android nella top 100 di Google Play. Le prestazioni di scorrimento per un elenco di oltre 1000 elementi rimangono stabili a 60 FPS sui dispositivi di fascia media grazie a tre meccanismi: pooling dei ViewHolder, calcolo degli aggiornamenti basato sulle differenze e caricamento asincrono dei dati.

Quando usare RecyclerView

RecyclerView è ottimale per: elenchi con numero sconosciuto di elementi (feed, chat, log), griglie a N colonne (gallerie, cataloghi), layout a cascata (bacheche Pinterest) ed elenchi con animazioni di aggiunta/rimozione. Per schermate semplici con 2–5 elementi, LinearLayout o ScrollView sono più semplici ed efficienti — RecyclerView aggiunge overhead.

Configurare la dipendenza

Per utilizzare RecyclerView, aggiungi la dipendenza a build.gradle (app): implementation 'androidx.recyclerview:recyclerview:1.4.0'. La versione API minima è 14 (Android 4.0). A partire da AndroidX RecyclerView 1.3.0, sono disponibili i moduli recyclerview-selection per la selezione degli elementi e recyclerview-swipe per i gesti di scorrimento.

Come funziona RecyclerView: tre componenti chiave

RecyclerView è diviso in tre livelli indipendenti: l'Adapter gestisce i dati e i ViewHolder, il LayoutManager si occupa del posizionamento degli elementi e l'ItemAnimator controlla le animazioni. Questa architettura consente di sostituire qualsiasi livello senza modificare gli altri — ad esempio, passare da LinearLayoutManager a GridLayoutManager senza cambiare il codice dell'Adapter.

ComponenteResponsabilitàImplementazione
AdapterCreare ViewHolder, collegare i dati alla View, notificare le modificheRecyclerView.Adapter<VH>
ViewHolderMemorizzare nella cache i riferimenti alle View, evitare findViewById()RecyclerView.ViewHolder
LayoutManagerPosizionare gli elementi, determinare la direzione di scorrimentoLinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager
ItemAnimatorAnimazione per aggiunta, rimozione, spostamento di elementiDefaultItemAnimator
ItemDecorationDisegnare divisori, spaziature, sfondi tra gli elementiRecyclerView.ItemDecoration

Ciclo di lavoro: (1) L'Adapter crea un ViewHolder tramite onCreateViewHolder(), (2) LayoutManager determina la posizione del nuovo View sullo schermo, (3) L'Adapter collega i dati tramite onBindViewHolder(), (4) durante lo scorrimento, i ViewHolder che escono dallo schermo entrano nel pool (RecycledViewPool) per il riutilizzo. Invece di creare nuovi View, quelli esistenti vengono riutilizzati — questo è il meccanismo chiave delle prestazioni.

Implementazione di ViewHolder in RecyclerView

ViewHolder è una classe che memorizza i riferimenti alle View (TextView, ImageView, ecc.) all'interno di un elemento dell'elenco. Senza ViewHolder, ogni scorrimento attiverebbe findViewById() — una delle operazioni più costose dell'interfaccia Android. ViewHolder elimina questa chiamata memorizzando nella cache i riferimenti dopo il binding iniziale.

kotlin
// Modello dati
data class Article(
    title: String,
    summary: String,
    author: String,
    imageUrl: String?
)

// ViewHolder — memorizza riferimenti a 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
    }
}

Regola pratica: ogni View nel layout dell'elemento deve essere dichiarata come proprietà ViewHolder con findViewById() esattamente una volta — nel costruttore. Il metodo bind() non chiama findViewById(), imposta solo testo, colori e listener. Questo approccio accelera lo scorrimento dell'elenco del 30–50% secondo Google (Android Performance Patterns, 2025).

Tipi di LayoutManager: scegliere la disposizione degli elementi

LayoutManager definisce come gli elementi sono posizionati all'interno di RecyclerView. Android fornisce tre implementazioni predefinite: LinearLayoutManager, GridLayoutManager e StaggeredGridLayoutManager. La scelta del LayoutManager influisce sulla percezione dei dati e sulle prestazioni di scorrimento.

LayoutManagerDisposizioneQuando usarloMetodo di configurazione
LinearLayoutManagerElenco (verticale o orizzontale)Feed, chat, notifiche, elenchi di prodottiLinearLayoutManager(context)
GridLayoutManagerGriglia a N colonneGallerie, cataloghi, icone, griglie di immaginiGridLayoutManager(context, spanCount)
StaggeredGridLayoutManagerGriglia a cascata (altezze diverse degli elementi)Bacheche Pinterest, note, gallerie masonryStaggeredGridLayoutManager(spanCount, orientation)
kotlin
// Configurare LinearLayoutManager in 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)

        // Ottimizzazione: dimensione fissa + pool
        recyclerView.setHasFixedSize(true)
        recyclerView.setItemViewCacheSize(20)

        // Divisore tra elementi
        val divider = DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)
        recyclerView.addItemDecoration(divider)
    }
}

Prestazioni: LinearLayoutManager con scorrimento verticale è l'opzione più veloce perché gli elementi sono disposti sequenzialmente e LayoutManager calcola le posizioni in O(1). GridLayoutManager richiede calcoli aggiuntivi per la divisione in colonne ma rimane efficiente con un spanCount fisso. StaggeredGridLayoutManager è il più lento dei tre poiché deve calcolare la posizione degli elementi a cascata considerando le altezze degli elementi vicini. Usalo solo quando sono visivamente richieste altezze di cella diverse.

Adapter e DiffUtil: aggiornamento efficiente dei dati

Adapter in RecyclerView implementa il pattern Adapter del GoF: trasforma i dati (List<T>) in ViewHolder visualizzati sullo schermo. Quando i dati cambiano, l'Adapter può notificare RecyclerView tramite notifyDataSetChanged(), notifyItemInserted() e metodi simili. Il problema è che notifyDataSetChanged() ridisegna tutti gli elementi visibili, causando scatti (jank).

kotlin
// Adapter con DiffUtil per aggiornamenti efficienti
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

    // Aggiornare elenco tramite DiffUtil
    fun updateArticles(newArticles: List<Article>) {
        val diffCallback = ArticleDiffCallback(articles, newArticles)
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        articles = newArticles
        diffResult.dispatchUpdatesTo(this)
    }
}

// Callback per 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 utilizza l'algoritmo di differenze di Eugene W. Myers, che calcola il numero minimo di operazioni (inserisci, rimuovi, sposta, modifica) per trasformare l'elenco vecchio in quello nuovo. Per un elenco di 100 elementi, DiffUtil funziona in 1–5 ms (Google, 2025). Per elenchi di grandi dimensioni (10000+), utilizza AsyncListDiffer o PagingDataAdapter della libreria Paging — eseguono i calcoli in un thread in background.

RecyclerView vs ListView: confronto

ListView è il predecessore di RecyclerView, introdotto in Android 1.0 (API 1). Visualizza anche elenchi ma non impone ViewHolder, non supporta LayoutManager e non può animare le modifiche. RecyclerView è stato progettato come sostituto di ListView con un'architettura più rigorosa e prestazioni migliori.

CriterioRecyclerViewListView
ViewHolderObbligatorio (architettura)Raccomandato ma non obbligatorio
LayoutManagerSeparazione: elenco, griglia, cascataSolo elenco verticale
Animazione modificheDefaultItemAnimator integratoNessun supporto integrato
Notifica modificheGranulare: notifyItemInserted/RemovedSolo notifyDataSetChanged() per l'intero elenco
DiffUtilSupporto tramite DiffUtil.CallbackNessun equivalente
DivisoriItemDecoration (personalizzato)android:divider (integrato)
Versione minimaAPI 14 (Android 4.0) tramite AndroidXAPI 1 (tutte le versioni)

Raccomandazione Google (Android Developers, 2026): utilizza RecyclerView per tutti i nuovi progetti. ListView può rimanere in basi di codice legacy dove la migrazione non giustifica il costo. RecyclerView offre prestazioni migliori con 100+ elementi, supporta lo scorrimento orizzontale e le griglie senza soluzioni alternative aggiuntive. In Android 15, ListView è ufficialmente contrassegnato come parzialmente deprecato.

Domande frequenti

RecyclerView non visualizza gli elementi — cosa fare?

Verifica tre condizioni: (1) l'Adapter è impostato tramite recyclerView.adapter = adapter, (2) il LayoutManager è impostato tramite recyclerView.layoutManager = LinearLayoutManager(context), (3) l'elenco dati non è vuoto e l'adapter è stato notificato (notifyDataSetChanged()). Un errore tipico è impostare i dati dopo aver chiamato notifyDataSetChanged(). I dati devono essere assegnati prima della notifica. Controlla la dimensione dell'elenco: adapter.itemCount deve essere maggiore di 0.

Perché RecyclerView scorre lentamente?

La lentezza durante lo scorrimento (jank) si verifica quando onBindViewHolder() esegue operazioni pesanti: caricamento di immagini senza cache, findViewById() dentro bind, calcoli complessi. Soluzioni: (1) utilizza Glide o Coil per il caricamento asincrono delle immagini, (2) sposta tutte le chiamate findViewById() nel costruttore di ViewHolder, (3) per i calcoli delle differenze, utilizza AsyncListDiffer. Attiva la profilazione GPU in Android Studio (Profile GPU Rendering) per trovare i fotogrammi lenti.

Come creare un RecyclerView orizzontale?

Passa l'orientamento a LayoutManager: LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false). Il secondo parametro è reverseLayout (false = da sinistra a destra). Per una griglia orizzontale, utilizza GridLayoutManager con orientamento orizzontale o un LinearSnapHelper personalizzato per lo scorrimento a pagine. Gli elenchi orizzontali sono adatti per caroselli di prodotti, immagini, categorie.

Come aggiungere un click listener a un elemento RecyclerView?

RecyclerView non ha un onClickListener integrato (a differenza di ListView con onItemClickListener). Implementalo in ViewHolder: passa un lambda al costruttore e imposta itemView.setOnClickListener. Esempio: class ArticleViewHolder(itemView: View, val onItemClick: (Article) -> Unit) : RecyclerView.ViewHolder(itemView). Chiama onItemClick(article) dentro bind(). Un'alternativa è utilizzare RecyclerView.addOnItemTouchListener() per la gestione dei gesti.

Cos'è RecycledViewPool e come configurarlo?

RecycledViewPool è un pool interno di ViewHolder che sono diventati invisibili durante lo scorrimento. Invece di essere distrutti, vengono conservati nel pool e riutilizzati. Per impostazione predefinita, il pool memorizza 5 ViewHolder per ogni tipo. Aumenta la dimensione per layout complessi: recyclerView.getRecycledViewPool().setMaxRecycledViews(VIEW_TYPE_NORMAL, maxCount). Se RecyclerView ha più tipi di View (viewType), il pool mantiene pile separate per ciascuno. Condividere un RecycledViewPool tra diversi RecyclerView consente di risparmiare memoria su schermate con elenchi annidati.

Riepilogo

  • RecyclerView è un componente moderno di Android Jetpack per elenchi e griglie con prestazioni fino a 60 FPS.
  • ViewHolder è un pattern obbligatorio per la memorizzazione nella cache delle View, eliminando findViewById() ad ogni scorrimento.
  • Adapter gestisce i dati e crea ViewHolder tramite onCreateViewHolder e onBindViewHolder.
  • LayoutManager — tre implementazioni: LinearLayoutManager (elenco), GridLayoutManager (griglia), StaggeredGridLayoutManager (cascata).
  • DiffUtil — algoritmo per aggiornamenti minimi dell'elenco: ridisegno granulare invece di aggiornamento completo.
  • RecyclerView è utilizzato nel 78% delle app Android nella top 100 ed è ufficialmente raccomandato da Google al posto di ListView.
  • Le prestazioni di RecyclerView sono ottenute tramite pooling dei ViewHolder, notifiche granulari e calcolo asincrono delle differenze.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche