Paginazione nello sviluppo mobile — cos'è, tipi e principio di funzionamento

Autore: IT Sectr Pubblicato: 2026-03-11 Tempo di lettura: 9 min

La paginazione è una tecnica di caricamento dei dati per pagine, utilizzata nelle applicazioni mobili e nei servizi web per gestire grandi insiemi di record. Secondo la Documentazione di Android Developers (2025), una corretta implementazione della paginazione riduce il carico sull'API, risparmia traffico e migliora l'esperienza utente. Il caricamento pagina per pagina consente all'applicazione di mostrare i contenuti gradualmente, senza attendere il caricamento completo di tutti i dati.

Punti chiave

  • Paginazione — metodo di caricamento di grandi insiemi di dati in porzioni per ottimizzare prestazioni e traffico.
  • Paginazione Offset utilizza un offset (page/offset) per la navigazione — semplice ma instabile con inserimenti frequenti.
  • Paginazione Cursor utilizza un cursore univoco dell'ultimo record — stabile quando i dati cambiano tra le richieste.
  • Paginazione Keyset filtra per una colonna con indice univoco — efficiente per tabelle grandi senza duplicati.
  • Paginazione basata sul tempo raggruppa i record per timestamp — comoda per feed di notizie e social network.

Cos'è la paginazione?

La paginazione (dal latino pagination — divisione in pagine) è una tecnica che suddivide un grande insieme di dati in porzioni sequenziali (pagine). Nelle applicazioni mobili, la paginazione viene utilizzata durante il caricamento di elenchi di messaggi, feed di notizie, cataloghi di prodotti, cronologia ordini e qualsiasi altra raccolta con un numero potenzialmente illimitato di record.

Senza paginazione, l'applicazione è costretta a caricare tutti i dati in una volta, causando lunghi tempi di attesa, elevato consumo di traffico e prestazioni instabili su dispositivi deboli. Una richiesta API con paginazione restituisce solo una porzione di dati e metainformazioni per caricare la successiva — in questo modo l'applicazione controlla la quantità di informazioni ricevute.

Le metriche principali della paginazione sono: dimensione della pagina (page size) — numero di record per pagina (di solito 10–50), e numero di pagina o cursore — un indicatore della posizione corrente nell'insieme. La scelta della dimensione della pagina dipende dal tipo di dati: per elementi compatti (nomi) bastano 20–30, per schede con immagini 10–15.

Perché la paginazione è necessaria nelle app mobili

I dispositivi mobili hanno risorse limitate: RAM, velocità del processore e limiti di traffico. La paginazione risolve tre compiti chiave: riduzione del consumo di memoria (solo gli elementi visibili sono memorizzati in memoria), accelerazione della prima visualizzazione (la prima porzione si carica più velocemente dell'intero insieme) e risparmio di traffico (i dati vengono caricati solo quando l'utente scorre l'elenco).

Principali tipi di paginazione

Esistono quattro tipi principali di paginazione, ciascuno risolve compiti specifici. La scelta del metodo dipende dai requisiti di consistenza dei dati, dall'architettura dell'API, dal tipo di archiviazione e dalla complessità accettabile di implementazione su client e server.

TipoPrincipio di funzionamentoStabilitàVelocità su grandi volumi
OffsetLIMIT + OFFSET in SQLbassadiminuisce con la crescita di OFFSET
CursorWHERE id > last_idaltastabile (O(log n))
KeysetWHERE key > last_keyaltastabile (O(log n))
Time-basedWHERE created_at < last_timemediastabile con indice

Quando usare quale tipo

La paginazione Offset è adatta per insiemi di dati statici o raramente aggiornati, quando la semplicità di implementazione è importante. Cursor e Keyset sono per dati dinamici con inserimenti frequenti. La paginazione basata sul tempo è per feed cronologici dove i record sono ordinati per data di creazione. Lo standard GraphQL Relay utilizza la paginazione cursore come unico metodo raccomandato.

Paginazione Offset: vantaggi e svantaggi

La paginazione Offset è il tipo più semplice di caricamento per pagine. Il client invia i parametri page e limit (o offset e limit), e il server applica SQL OFFSET e LIMIT. Ad esempio, page=2, limit=20 restituisce i record dal 21 al 40. Questo metodo è intuitivo e facile da implementare su qualsiasi stack.

python
from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items")
async def get_items(
    page: int = Query(default=1, ge=1),
    limit: int = Query(default=20, le=100)
):
    offset = (page - 1) * limit
    items = await fetch_items(offset, limit)
    total = await count_items()
    return {
        "items": items,
        "total": total,
        "page": page,
        "pages": (total + limit - 1) // limit
    }

Il problema dell'inconsistenza dei dati

Lo svantaggio principale della paginazione Offset è il problema di record mancanti e duplicati. Se nuovi record vengono aggiunti alla tabella tra due richieste, OFFSET si sposta: l'utente potrebbe vedere lo stesso record due volte o perderne uno nuovo. Questo è critico per feed di notizie e chat dove la consistenza è importante.

Un altro problema è il degrado delle prestazioni su grandi OFFSET. Il database deve scansionare e saltare i primi offset record prima di restituire il risultato. Con offset=100000 anche con LIMIT 20, il server impiegherà un tempo notevole per la scansione. PostgreSQL e MySQL mostrano un calo lineare della velocità con la crescita di OFFSET.

Quando Offset è ancora buono

La paginazione Offset rimane la scelta migliore per: pannelli di amministrazione (i dati cambiano raramente, è necessaria la navigazione tra pagine), report e log storici (istantanea fissa dei dati), cataloghi con filtri (si può passare a qualsiasi pagina). Offset è anche il più semplice da implementare sul client — RecyclerView con Paging 3 lo supporta nativamente.

Paginazione Keyset e basata sul tempo

La paginazione Keyset utilizza una chiave univoca (di solito la chiave primaria) per filtrare i record. Invece di OFFSET, la query utilizza WHERE id > last_seen_id. Ciò garantisce prestazioni stabili indipendentemente dal numero di record e assenza di duplicati negli inserimenti, poiché i nuovi record hanno sempre un id più grande.

sql
-- Paginazione Offset (problematica)
SELECT * FROM posts
ORDER BY id
LIMIT 20 OFFSET 100;

-- Paginazione Keyset (stabile)
SELECT * FROM posts
WHERE id > 100
ORDER BY id
LIMIT 20;

Paginazione basata sul tempo

La paginazione basata sul tempo (o cursore per tempo) utilizza il timestamp created_at per la navigazione. Il client invia il timestamp dell'ultimo record caricato e il server restituisce i record creati prima o dopo quel timestamp. Questo metodo è popolare nei social network e nei feed di notizie dove l'ordine dei record è determinato dall'ora di pubblicazione.

Una caratteristica della paginazione basata sul tempo sono i possibili duplicati se due record vengono creati nello stesso millisecondo. Per eliminare questo problema, combina una chiave basata sul tempo con un id univoco: WHERE (created_at, id) < (last_time, last_id). Tale cursore composito garantisce l'univocità di ogni record e un ordinamento preciso.

Confronto tra Keyset e basata sul tempo

La paginazione Keyset richiede una colonna con un valore univoco e monotonicamente crescente (id auto-incrementante, UUID v7). Quella basata sul tempo è adatta per qualsiasi tabella con created_at, ma richiede una gestione aggiuntiva dei duplicati. La differenza principale: Keyset funziona stabilmente con qualsiasi operazione di inserimento, mentre quella basata sul tempo è sensibile a timestamp identici.

Come scegliere il tipo di paginazione per il tuo progetto

La scelta del tipo di paginazione dipende dalla natura dei dati e dai requisiti dell'esperienza utente. Di seguito sono riportate raccomandazioni per scenari tipici nello sviluppo mobile. Non esiste una soluzione universale — ogni metodo ha un dominio in cui è ottimale.

  • Chat / Messenger — Paginazione Cursor (per id messaggio). I nuovi messaggi appaiono in alto, il cursore non si perde.
  • Feed di notizie — Paginazione basata sul tempo (per created_at). I record sono ordinati per tempo, la cronologia è importante.
  • Catalogo prodotti — Paginazione Offset. L'utente può passare a una pagina specifica, i dati cambiano raramente.
  • Cronologia ordini — Paginazione Cursor. La stabilità è importante perché nuovi ordini vengono aggiunti tra i caricamenti.
  • Commenti — Paginazione Keyset. Ogni commento ha un id univoco, grandi volumi senza duplicati.

Implementazione su Android con Paging 3

La libreria Android Paging 3 supporta tutti i tipi di paginazione tramite PagingSource. Per Offset — PagingSource con chiave Int (page), per Cursor — con chiave String o Long (cursor). PagingSource gestisce automaticamente il caricamento, la memorizzazione nella cache e i tentativi in caso di errori.

kotlin
class PostPagingSource(
    private val api: PostApi
) : PagingSource<Long, Post>() {

    override suspend fun load(
        params: LoadParams<Long>
    ): LoadResult<Long, Post> {
        val cursor = params.key ?: Long.MAX_VALUE
        return try {
            val response = api.getPosts(cursor, params.loadSize)
            LoadResult.Page(
                data = response.items,
                prevKey = null,
                nextKey = response.items.lastOrNull()?.id
            )
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }

    override fun getRefreshKey(state: PagingState<Long, Post>): Long? {
        return state.anchorPosition?.let {
            state.closestItemToPosition(it)?.id
        }
    }
}

Raccomandazioni sulla dimensione della pagina

La dimensione della pagina influisce sulla velocità di caricamento e sulla percezione delle prestazioni. Per le applicazioni mobili, l'intervallo ottimale è 10–25 elementi per pagina. Meno di 10 comporta troppe richieste all'API e uno scorrimento a scatti. Più di 25 comporta un caricamento lento della prima porzione su reti lente.

Per immagini e video, riduci la dimensione della pagina a 5–10, poiché ogni elemento richiede tempo aggiuntivo per caricare i media. Per elenchi di testo (commenti, log), la dimensione può essere aumentata a 30–50 record. Si consiglia di rendere configurabile la dimensione della pagina tramite API in modo che il client possa adattarsi a diverse condizioni di rete.

Domande frequenti

Cos'è la paginazione in parole semplici?

La paginazione è il caricamento dei dati in porzioni, non tutto in una volta. Come in un libro: leggi una pagina, poi passi alla successiva. In un'app, significa che scorrendo un elenco si carica il lotto successivo di dati, non l'intero elenco, risparmiando traffico e memoria.

In cosa differisce Offset da Cursor?

Offset conta i record: “salta 20, restituisci i successivi 10.” Se un nuovo record viene aggiunto tra i caricamenti, la numerazione si perde. Cursor utilizza l'identificatore univoco dell'ultimo record: “restituisci 10 record dopo ID = 100.” I nuovi record non influenzano la posizione.

Qual è la dimensione di pagina ottimale per la paginazione?

Per le applicazioni mobili, 10–25 elementi è ottimale. Per elenchi con immagini 5–10, per feed di testo 20–30. La dimensione dipende dalla dimensione media di ogni elemento: più pesante è l'elemento, più piccola deve essere la pagina per una visualizzazione rapida.

Come implementare la paginazione in RecyclerView?

Usa la libreria Paging 3 di Android Jetpack. Fornisce PagingSource per il caricamento, PagingData per flussi reattivi e PagingDataAdapter per il caricamento automatico durante lo scorrimento. La libreria supporta la paginazione Offset, Cursor e Keyset tramite un PagingSource personalizzato.

Cos'è lo scroll infinito e in cosa si differenzia dalla paginazione?

Lo scroll infinito è un pattern dell'interfaccia in cui un nuovo lotto di dati viene caricato automaticamente quando ci si avvicina alla fine dell'elenco. La paginazione è il meccanismo di caricamento dei dati in lotti, mentre lo scroll infinito è un modo per visualizzarlo. Un'alternativa è il pulsante “Carica altri”.

Riepilogo

  • Paginazione — tecnica di caricamento dei dati in porzioni, essenziale per applicazioni mobili con qualsiasi tipo di elenco.
  • Paginazione Offset è semplice da implementare ma soffre di inconsistenza negli inserimenti e degrado delle prestazioni su grandi OFFSET.
  • Paginazione Cursor utilizza un identificatore univoco per la navigazione — stabile ed efficiente su qualsiasi volume.
  • Paginazione Keyset filtra per chiave primaria, offrendo massime prestazioni grazie all'uso degli indici.
  • Paginazione basata sul tempo raggruppa i record per timestamp — ideale per feed cronologici e social network.
  • La scelta del metodo dipende dalla natura dei dati: per dati dinamici Cursor/Keyset, per statici Offset, per feed Time-based.
  • Paging 3 su Android e le soluzioni standard di cursore su iOS/web forniscono infrastruttura pronta per qualsiasi tipo di paginazione.

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